diff options
author | eschaeffer <eschaeffer@unknown> | 2001-01-25 15:11:05 +0000 |
---|---|---|
committer | eschaeffer <eschaeffer@unknown> | 2001-01-25 15:11:05 +0000 |
commit | 2927de757166c41a845ecd68a360c73b14e77017 (patch) | |
tree | 80c26d0a46a03963ec00a3a5469268cbc73f3444 /src | |
parent | 2c4d2fab77151a9a9ca4fbce43747be2e0464e3a (diff) | |
download | xmlgraphics-fop-2927de757166c41a845ecd68a360c73b14e77017.tar.gz xmlgraphics-fop-2927de757166c41a845ecd68a360c73b14e77017.zip |
Modified to support new FontState class.
PR:
Obtained from:
Submitted by:
Reviewed by:
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@193987 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r-- | src/org/apache/fop/render/pdf/SVGRenderer.java | 5050 | ||||
-rw-r--r-- | src/org/apache/fop/svg/SVG.java | 369 |
2 files changed, 2711 insertions, 2708 deletions
diff --git a/src/org/apache/fop/render/pdf/SVGRenderer.java b/src/org/apache/fop/render/pdf/SVGRenderer.java index 2296ce7ca..747051334 100644 --- a/src/org/apache/fop/render/pdf/SVGRenderer.java +++ b/src/org/apache/fop/render/pdf/SVGRenderer.java @@ -1,7 +1,7 @@ /*-- $Id$ -- ============================================================================ - The Apache Software License, Version 1.1 + The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999 The Apache Software Foundation. All rights reserved. @@ -88,2529 +88,2531 @@ import java.util.Hashtable; */ public class SVGRenderer { - /** the PDF Document being created */ - protected PDFDocument pdfDoc; - - protected FontState fontState; - - /** the /Resources object of the PDF document being created */ - // protected PDFResources pdfResources; - - /** the current stream to add PDF commands to */ - StringWriter currentStream = new StringWriter(); - - /** the current (internal) font name */ - protected String currentFontName; - - /** the current font size in millipoints */ - protected int currentFontSize; - - /** the current vertical position in millipoints from bottom */ - protected int currentYPosition = 0; - - /** the current horizontal position in millipoints from left */ - protected int currentXPosition = 0; - - /** the current colour for use in svg */ - private PDFColor currentColour = new PDFColor(0, 0, 0); - - /** - * create the SVG renderer - */ - public SVGRenderer(FontState fs, PDFDocument doc, String font, - int size, int xpos, int ypos) { - pdfDoc = doc; - currentFontName = font; - currentFontSize = size; - currentYPosition = ypos; - currentXPosition = xpos; - fontState = fs; - } - - public String getString() { - return currentStream.toString(); - } - - /** - * Renders an SVG element in an SVG document. - * This renders each of the child elements. - */ - protected void renderSVG(SVGSVGElement svg, int x, int y) { - NodeList nl = svg.getChildNodes(); - for (int count = 0; count < nl.getLength(); count++) { - Node n = nl.item(count); - if (n instanceof SVGElement) { - renderElement((SVGElement) n, x, y); - } - } - } - - public void renderGArea(SVGGElement area, int posx, int posy) { - NodeList nl = area.getChildNodes(); - for (int count = 0; count < nl.getLength(); count++) { - Node n = nl.item(count); - if (n instanceof SVGElement) { - renderElement((SVGElement) n, posx, posy); - } - } - } - - /** - * Handles the SVG switch element. - * The switch determines which of its child elements should be rendered - * according to the required extensions, required features and system language. - */ - protected void handleSwitchElement(int posx, int posy, - SVGSwitchElement ael) { - SVGStringList relist = ael.getRequiredExtensions(); - SVGStringList rflist = ael.getRequiredFeatures(); - SVGStringList sllist = ael.getSystemLanguage(); - NodeList nl = ael.getChildNodes(); - choices: - for (int count = 0; count < nl.getLength(); count++) { - org.w3c.dom.Node n = nl.item(count); - // only render the first child that has a valid - // test data - if (n instanceof GraphicElement) { - GraphicElement graphic = (GraphicElement) n; - SVGStringList grelist = graphic.getRequiredExtensions(); - // if null it evaluates to true - if (grelist != null) { - if (grelist.getNumberOfItems() == 0) { - if ((relist != null) && - relist.getNumberOfItems() != 0) { - continue choices; - } - } - for (int i = 0; i < grelist.getNumberOfItems(); i++) { - String str = (String) grelist.getItem(i); - if (relist == null) { - // use default extension set - // currently no extensions are supported - // if(!(str.equals("http:// ??"))) { - continue choices; - // } - } else { - } - } - } - SVGStringList grflist = graphic.getRequiredFeatures(); - if (grflist != null) { - if (grflist.getNumberOfItems() == 0) { - if ((rflist != null) && - rflist.getNumberOfItems() != 0) { - continue choices; - } - } - for (int i = 0; i < grflist.getNumberOfItems(); i++) { - String str = (String) grflist.getItem(i); - if (rflist == null) { - // use default feature set - if (!(str.equals("org.w3c.svg.static") || - str.equals("org.w3c.dom.svg.all"))) { - continue choices; - } - } else { - boolean found = false; - for (int j = 0; - j < rflist.getNumberOfItems(); j++) { - if (rflist.getItem(j).equals(str)) { - found = true; - break; - } - } - if (!found) - continue choices; - } - } - } - SVGStringList gsllist = graphic.getSystemLanguage(); - if (gsllist != null) { - if (gsllist.getNumberOfItems() == 0) { - if ((sllist != null) && - sllist.getNumberOfItems() != 0) { - continue choices; - } - } - for (int i = 0; i < gsllist.getNumberOfItems(); i++) { - String str = (String) gsllist.getItem(i); - if (sllist == null) { - // use default feature set - if (!(str.equals("en"))) { - continue choices; - } - } else { - boolean found = false; - for (int j = 0; - j < sllist.getNumberOfItems(); j++) { - if (sllist.getItem(j).equals(str)) { - found = true; - break; - } - } - if (!found) - continue choices; - } - } - } - renderElement((SVGElement) n, posx, posy); - // only render the first valid one - break; - } - } - } - - /** - * add a line to the current stream - * - * @param x1 the start x location in millipoints - * @param y1 the start y location in millipoints - * @param x2 the end x location in millipoints - * @param y2 the end y location in millipoints - * @param th the thickness in millipoints - * @param r the red component - * @param g the green component - * @param b the blue component - */ - protected void addLine(float x1, float y1, float x2, float y2, - DrawingInstruction di) { - String str; - PDFNumber pdfNumber = new PDFNumber(); - str = "" + pdfNumber.doubleOut(x1) + " " + pdfNumber.doubleOut(y1) + " m " + pdfNumber.doubleOut(x2) + " " + pdfNumber.doubleOut(y2) + " l"; - if (di != null && di.fill) - currentStream.write(str + " f\n"); // ?? - currentStream.write(str + " S\n"); - } - - /** - * Add an SVG circle - * Uses bezier curves to approximate the shape of a circle. - */ - protected void addCircle(float cx, float cy, float r, - DrawingInstruction di) { - PDFNumber pdfNumber = new PDFNumber(); - String str; - str = "" + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut((cy - r)) + " m\n" + "" + - pdfNumber.doubleOut((cx + 21 * r / 40f)) + " " + pdfNumber.doubleOut((cy - r)) + " " + - pdfNumber.doubleOut((cx + r)) + " " + pdfNumber.doubleOut((cy - 21 * r / 40f)) + " " + - pdfNumber.doubleOut((cx + r)) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut((cx + r)) + " " + - pdfNumber.doubleOut((cy + 21 * r / 40f)) + " " + pdfNumber.doubleOut((cx + 21 * r / 40f)) + - " " + pdfNumber.doubleOut((cy + r)) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut((cy + r)) + " c\n" + - "" + pdfNumber.doubleOut((cx - 21 * r / 40f)) + " " + pdfNumber.doubleOut((cy + r)) + " " + - pdfNumber.doubleOut(cx - r) + " " + pdfNumber.doubleOut(cy + 21 * r / 40f) + " " + - pdfNumber.doubleOut(cx - r) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut(cx - r) + " " + - pdfNumber.doubleOut(cy - 21 * r / 40f) + " " + pdfNumber.doubleOut(cx - 21 * r / 40f) + - " " + pdfNumber.doubleOut(cy - r) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy - r) + " c\n"; - - currentStream.write(str); - doDrawing(di); - } - - /** - * Add an SVG ellips - * Uses bezier curves to approximate the shape of an ellipse. - */ - protected void addEllipse(float cx, float cy, float rx, float ry, - DrawingInstruction di) { - PDFNumber pdfNumber = new PDFNumber(); - String str; - str = "" + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy - ry) + " m\n" + "" + - pdfNumber.doubleOut(cx + 21 * rx / 40f) + " " + pdfNumber.doubleOut(cy - ry) + " " + - pdfNumber.doubleOut(cx + rx) + " " + pdfNumber.doubleOut(cy - 21 * ry / 40f) + " " + - pdfNumber.doubleOut(cx + rx) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut(cx + rx) + " " + - pdfNumber.doubleOut(cy + 21 * ry / 40f) + " " + pdfNumber.doubleOut(cx + 21 * rx / 40f) + - " " + pdfNumber.doubleOut(cy + ry) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy + ry) + - " c\n" + "" + pdfNumber.doubleOut(cx - 21 * rx / 40f) + " " + pdfNumber.doubleOut(cy + ry) + - " " + pdfNumber.doubleOut(cx - rx) + " " + pdfNumber.doubleOut(cy + 21 * ry / 40f) + " " + - pdfNumber.doubleOut(cx - rx) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut(cx - rx) + " " + - pdfNumber.doubleOut(cy - 21 * ry / 40f) + " " + pdfNumber.doubleOut(cx - 21 * rx / 40f) + - " " + pdfNumber.doubleOut(cy - ry) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy - ry) + " c\n"; - currentStream.write(str); - doDrawing(di); - } - - /** - * add an SVG rectangle to the current stream. - * If there are curved edges then these are rendered using bezier curves. - * - * @param x the x position of left edge - * @param y the y position of top edge - * @param w the width - * @param h the height - * @param rx the x radius curved edge - * @param ry the y radius curved edge - */ - protected void addRect(float x, float y, float w, float h, - float rx, float ry, DrawingInstruction di) { - PDFNumber pdfNumber = new PDFNumber(); - String str = ""; - if (rx == 0.0 && ry == 0.0) { - str = "" + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y) + " " + pdfNumber.doubleOut(w) + " " + pdfNumber.doubleOut(h) + " re\n"; - } else { - if (ry == 0.0) - ry = rx; - if (rx > w / 2.0f) - rx = w / 2.0f; - if (ry > h / 2.0f) - ry = h / 2.0f; - str = "" + pdfNumber.doubleOut(x + rx) + " " + pdfNumber.doubleOut(y) + " m\n"; - str += "" + pdfNumber.doubleOut(x + w - rx) + " " + pdfNumber.doubleOut(y) + " l\n"; - str += "" + pdfNumber.doubleOut(x + w - 19 * rx / 40) + " " + pdfNumber.doubleOut(y) + " " + - pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + 19 * ry / 40) + " " + - pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + ry) + " c\n"; - str += "" + pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + h - ry) + " l\n"; - str += "" + pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + h - 19 * ry / 40) + " " + - pdfNumber.doubleOut(x + w - 19 * rx / 40) + " " + pdfNumber.doubleOut(y + h) + " " + - pdfNumber.doubleOut(x + w - rx) + " " + pdfNumber.doubleOut(y + h) + " c\n"; - str += "" + pdfNumber.doubleOut(x + rx) + " " + pdfNumber.doubleOut(y + h) + " l\n"; - str += "" + pdfNumber.doubleOut(x + 19 * rx / 40) + " " + pdfNumber.doubleOut(y + h) + " " + pdfNumber.doubleOut(x) + - " " + pdfNumber.doubleOut(y + h - 19 * ry / 40) + " " + pdfNumber.doubleOut(x) + " " + - pdfNumber.doubleOut(y + h - ry) + " c\n"; - str += "" + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y + ry) + " l\n"; - str += "" + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y + 19 * ry / 40) + " " + - pdfNumber.doubleOut(x + 19 * rx / 40) + " " + pdfNumber.doubleOut(y) + " " + pdfNumber.doubleOut(x + rx) + - " " + pdfNumber.doubleOut(y) + " c\n"; - } - currentStream.write(str); - doDrawing(di); - } - - /** - * Adds an SVG path to the current streem. - * An SVG path is made up of a list of drawing instructions that are rendered - * out in order. - * Arcs don't work. - */ - protected void addPath(Vector points, int posx, int posy, - DrawingInstruction di) { - PDFNumber pdfNumber = new PDFNumber(); - SVGPathSegImpl pathmoveto = null; - float lastx = 0; - float lasty = 0; - float lastmovex = 0; - float lastmovey = 0; - float[] cxs; - float tempx; - float tempy; - float lastcx = 0; - float lastcy = 0; - for (Enumeration e = points.elements(); e.hasMoreElements();) { - SVGPathSegImpl pc = (SVGPathSegImpl) e.nextElement(); - float[] vals = pc.getValues(); - switch (pc.getPathSegType()) { - case SVGPathSeg.PATHSEG_MOVETO_ABS: - pathmoveto = pc; - lastx = vals[0]; - lasty = vals[1]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " m\n"); - lastcx = 0; - lastcy = 0; - lastmovex = lastx; - lastmovey = lasty; - break; - case SVGPathSeg.PATHSEG_MOVETO_REL: - // the test cases seem to interprete this command differently - // it seems if there is an 'm' then the current path is closed - // then the point is move to a place relative to the point - // after doing the close - if (pathmoveto == null) { - lastx += vals[0]; - lasty += vals[1]; - pathmoveto = pc; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " m\n"); - } else { - lastx += vals[0]; - lasty += vals[1]; - pathmoveto = pc; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - } - lastmovex = lastx; - lastmovey = lasty; - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_LINETO_ABS: - lastx = vals[0]; - lasty = vals[1]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_LINETO_REL: - lastx += vals[0]; - lasty += vals[1]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: - lasty = vals[0]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: - lasty += vals[0]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: - lastx = vals[0]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: - lastx += vals[0]; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - lastcx = 0; - lastcy = 0; - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: - lastx = vals[4]; - lasty = vals[5]; - lastcx = vals[2]; - lastcy = vals[3]; - currentStream.write(pdfNumber.doubleOut(vals[0]) + " " + pdfNumber.doubleOut(vals[1]) + - " " + pdfNumber.doubleOut(vals[2]) + " " + pdfNumber.doubleOut(vals[3]) + " " + - pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " c\n"); - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: - currentStream.write(pdfNumber.doubleOut(vals[0] + lastx) + " " + - pdfNumber.doubleOut(vals[1] + lasty) + " " + - pdfNumber.doubleOut(vals[2] + lastx) + " " + - pdfNumber.doubleOut(vals[3] + lasty) + " " + - pdfNumber.doubleOut(vals[4] + lastx) + " " + - pdfNumber.doubleOut(vals[5] + lasty) + " c\n"); - lastcx = vals[2] + lastx; - lastcy = vals[3] + lasty; - lastx += vals[4]; - lasty += vals[5]; - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: - if (lastcx == 0) { - lastcx = lastx; - } - if (lastcy == 0) { - lastcy = lasty; - } - lastcx = lastx + (lastx - lastcx); - lastcy = lasty + (lasty - lastcy); - lastx = vals[2]; - lasty = vals[3]; - currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + - pdfNumber.doubleOut(vals[0]) + " " + pdfNumber.doubleOut(vals[1]) + " " + - pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " c\n"); - lastcx = vals[0]; - lastcy = vals[1]; - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: - if (lastcx == 0) { - lastcx = lastx; - } - if (lastcy == 0) { - lastcy = lasty; - } - lastcx = lastx + (lastx - lastcx); - lastcy = lasty + (lasty - lastcy); - currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + - pdfNumber.doubleOut(vals[0] + lastx) + " " + - pdfNumber.doubleOut(vals[1] + lasty) + " " + - pdfNumber.doubleOut(vals[2] + lastx) + " " + - pdfNumber.doubleOut(vals[3] + lasty) + " c\n"); - lastcx = (vals[0] + lastx); - lastcy = (vals[1] + lasty); - lastx += vals[2]; - lasty += vals[3]; - break; - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: - if (lastcx == 0) { - lastcx = lastx; - } - if (lastcy == 0) { - lastcy = lasty; - } - tempx = lastx; - tempy = lasty; - lastx = vals[2]; - lasty = vals[3]; - currentStream.write(pdfNumber.doubleOut(vals[0]) + " " + pdfNumber.doubleOut(vals[1]) + " " + - pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " y\n"); - cxs = calculateLastControl(tempx, tempy, lastx, lasty, -tempx + vals[0], -tempy + vals[1]); - lastcx = cxs[0]; - lastcy = cxs[1]; - break; - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: - if (lastcx == 0) { - lastcx = lastx; - } - if (lastcy == 0) { - lastcy = lasty; - } - currentStream.write(pdfNumber.doubleOut(vals[0] + lastx) + " " + pdfNumber.doubleOut(vals[1] + lasty) + " " + - pdfNumber.doubleOut(vals[2] + lastx) + " " + - pdfNumber.doubleOut(vals[3] + lasty) + " y\n"); - cxs = calculateLastControl(lastx, lasty, lastx + vals[2], lasty + vals[3], vals[0], vals[1]); - lastcx = cxs[0]; - lastcy = cxs[1]; - lastx += vals[2]; - lasty += vals[3]; - break; - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: - if (lastcx == 0) { - lastcx = lastx; - } - if (lastcy == 0) { - lastcy = lasty; - } - tempx = lastx; - tempy = lasty; - lastcx = lastx + (lastx - lastcx); - lastcy = lasty + (lasty - lastcy); - lastx = vals[0]; - lasty = vals[1]; - currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + - pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " y\n"); - cxs = calculateLastControl(tempx, tempy, lastx, lasty, -tempx + lastcx, -tempy + lastcy); - lastcx = cxs[0]; - lastcy = cxs[1]; - break; - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: - if (lastcx == 0) { - lastcx = lastx; - } - if (lastcy == 0) { - lastcy = lasty; - } - lastcx = lastx + (lastx - lastcx); - lastcy = lasty + (lasty - lastcy); - currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + - pdfNumber.doubleOut(vals[0] + lastx) + " " + - pdfNumber.doubleOut(vals[1] + lasty) + " y\n"); - cxs = calculateLastControl(lastx, lasty, lastx + vals[0], lasty + vals[1], -lastx + lastcx, -lasty + lastcy); - lastcx = cxs[0]; - lastcy = cxs[1]; - lastx += vals[0]; - lasty += vals[1]; - break; - // get angle between the two points - // then get angle of points to centre (ie. both points are on the - // apogee and perigee of the ellipse) - // then work out the direction from flags - case SVGPathSeg.PATHSEG_ARC_ABS: - { + /** the PDF Document being created */ + protected PDFDocument pdfDoc; + + protected FontState fontState; + + /** the /Resources object of the PDF document being created */ + // protected PDFResources pdfResources; + + /** the current stream to add PDF commands to */ + StringWriter currentStream = new StringWriter(); + + /** the current (internal) font name */ + protected String currentFontName; + + /** the current font size in millipoints */ + protected int currentFontSize; + + /** the current vertical position in millipoints from bottom */ + protected int currentYPosition = 0; + + /** the current horizontal position in millipoints from left */ + protected int currentXPosition = 0; + + /** the current colour for use in svg */ + private PDFColor currentColour = new PDFColor(0, 0, 0); + + /** + * create the SVG renderer + */ + public SVGRenderer(FontState fs, PDFDocument doc, String font, + int size, int xpos, int ypos) { + pdfDoc = doc; + currentFontName = font; + currentFontSize = size; + currentYPosition = ypos; + currentXPosition = xpos; + fontState = fs; + } + + public String getString() { + return currentStream.toString(); + } + + /** + * Renders an SVG element in an SVG document. + * This renders each of the child elements. + */ + protected void renderSVG(SVGSVGElement svg, int x, int y) { + NodeList nl = svg.getChildNodes(); + for (int count = 0; count < nl.getLength(); count++) { + Node n = nl.item(count); + if (n instanceof SVGElement) { + renderElement((SVGElement) n, x, y); + } + } + } + + public void renderGArea(SVGGElement area, int posx, int posy) { + NodeList nl = area.getChildNodes(); + for (int count = 0; count < nl.getLength(); count++) { + Node n = nl.item(count); + if (n instanceof SVGElement) { + renderElement((SVGElement) n, posx, posy); + } + } + } + + /** + * Handles the SVG switch element. + * The switch determines which of its child elements should be rendered + * according to the required extensions, required features and system language. + */ + protected void handleSwitchElement(int posx, int posy, + SVGSwitchElement ael) { + SVGStringList relist = ael.getRequiredExtensions(); + SVGStringList rflist = ael.getRequiredFeatures(); + SVGStringList sllist = ael.getSystemLanguage(); + NodeList nl = ael.getChildNodes(); + choices: + for (int count = 0; count < nl.getLength(); count++) { + org.w3c.dom.Node n = nl.item(count); + // only render the first child that has a valid + // test data + if (n instanceof GraphicElement) { + GraphicElement graphic = (GraphicElement) n; + SVGStringList grelist = graphic.getRequiredExtensions(); + // if null it evaluates to true + if (grelist != null) { + if (grelist.getNumberOfItems() == 0) { + if ((relist != null) && + relist.getNumberOfItems() != 0) { + continue choices; + } + } + for (int i = 0; i < grelist.getNumberOfItems(); i++) { + String str = (String) grelist.getItem(i); + if (relist == null) { + // use default extension set + // currently no extensions are supported + // if(!(str.equals("http:// ??"))) { + continue choices; + // } + } else { + } + } + } + SVGStringList grflist = graphic.getRequiredFeatures(); + if (grflist != null) { + if (grflist.getNumberOfItems() == 0) { + if ((rflist != null) && + rflist.getNumberOfItems() != 0) { + continue choices; + } + } + for (int i = 0; i < grflist.getNumberOfItems(); i++) { + String str = (String) grflist.getItem(i); + if (rflist == null) { + // use default feature set + if (!(str.equals("org.w3c.svg.static") || + str.equals("org.w3c.dom.svg.all"))) { + continue choices; + } + } else { + boolean found = false; + for (int j = 0; + j < rflist.getNumberOfItems(); j++) { + if (rflist.getItem(j).equals(str)) { + found = true; + break; + } + } + if (!found) + continue choices; + } + } + } + SVGStringList gsllist = graphic.getSystemLanguage(); + if (gsllist != null) { + if (gsllist.getNumberOfItems() == 0) { + if ((sllist != null) && + sllist.getNumberOfItems() != 0) { + continue choices; + } + } + for (int i = 0; i < gsllist.getNumberOfItems(); i++) { + String str = (String) gsllist.getItem(i); + if (sllist == null) { + // use default feature set + if (!(str.equals("en"))) { + continue choices; + } + } else { + boolean found = false; + for (int j = 0; + j < sllist.getNumberOfItems(); j++) { + if (sllist.getItem(j).equals(str)) { + found = true; + break; + } + } + if (!found) + continue choices; + } + } + } + renderElement((SVGElement) n, posx, posy); + // only render the first valid one + break; + } + } + } + + /** + * add a line to the current stream + * + * @param x1 the start x location in millipoints + * @param y1 the start y location in millipoints + * @param x2 the end x location in millipoints + * @param y2 the end y location in millipoints + * @param th the thickness in millipoints + * @param r the red component + * @param g the green component + * @param b the blue component + */ + protected void addLine(float x1, float y1, float x2, float y2, + DrawingInstruction di) { + String str; + PDFNumber pdfNumber = new PDFNumber(); + str = "" + pdfNumber.doubleOut(x1) + " " + pdfNumber.doubleOut(y1) + " m " + pdfNumber.doubleOut(x2) + " " + pdfNumber.doubleOut(y2) + " l"; + if (di != null && di.fill) + currentStream.write(str + " f\n"); // ?? + currentStream.write(str + " S\n"); + } + + /** + * Add an SVG circle + * Uses bezier curves to approximate the shape of a circle. + */ + protected void addCircle(float cx, float cy, float r, + DrawingInstruction di) { + PDFNumber pdfNumber = new PDFNumber(); + String str; + str = "" + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut((cy - r)) + " m\n" + "" + + pdfNumber.doubleOut((cx + 21 * r / 40f)) + " " + pdfNumber.doubleOut((cy - r)) + " " + + pdfNumber.doubleOut((cx + r)) + " " + pdfNumber.doubleOut((cy - 21 * r / 40f)) + " " + + pdfNumber.doubleOut((cx + r)) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut((cx + r)) + " " + + pdfNumber.doubleOut((cy + 21 * r / 40f)) + " " + pdfNumber.doubleOut((cx + 21 * r / 40f)) + + " " + pdfNumber.doubleOut((cy + r)) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut((cy + r)) + " c\n" + + "" + pdfNumber.doubleOut((cx - 21 * r / 40f)) + " " + pdfNumber.doubleOut((cy + r)) + " " + + pdfNumber.doubleOut(cx - r) + " " + pdfNumber.doubleOut(cy + 21 * r / 40f) + " " + + pdfNumber.doubleOut(cx - r) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut(cx - r) + " " + + pdfNumber.doubleOut(cy - 21 * r / 40f) + " " + pdfNumber.doubleOut(cx - 21 * r / 40f) + + " " + pdfNumber.doubleOut(cy - r) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy - r) + " c\n"; + + currentStream.write(str); + doDrawing(di); + } + + /** + * Add an SVG ellips + * Uses bezier curves to approximate the shape of an ellipse. + */ + protected void addEllipse(float cx, float cy, float rx, float ry, + DrawingInstruction di) { + PDFNumber pdfNumber = new PDFNumber(); + String str; + str = "" + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy - ry) + " m\n" + "" + + pdfNumber.doubleOut(cx + 21 * rx / 40f) + " " + pdfNumber.doubleOut(cy - ry) + " " + + pdfNumber.doubleOut(cx + rx) + " " + pdfNumber.doubleOut(cy - 21 * ry / 40f) + " " + + pdfNumber.doubleOut(cx + rx) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut(cx + rx) + " " + + pdfNumber.doubleOut(cy + 21 * ry / 40f) + " " + pdfNumber.doubleOut(cx + 21 * rx / 40f) + + " " + pdfNumber.doubleOut(cy + ry) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy + ry) + + " c\n" + "" + pdfNumber.doubleOut(cx - 21 * rx / 40f) + " " + pdfNumber.doubleOut(cy + ry) + + " " + pdfNumber.doubleOut(cx - rx) + " " + pdfNumber.doubleOut(cy + 21 * ry / 40f) + " " + + pdfNumber.doubleOut(cx - rx) + " " + pdfNumber.doubleOut(cy) + " c\n" + "" + pdfNumber.doubleOut(cx - rx) + " " + + pdfNumber.doubleOut(cy - 21 * ry / 40f) + " " + pdfNumber.doubleOut(cx - 21 * rx / 40f) + + " " + pdfNumber.doubleOut(cy - ry) + " " + pdfNumber.doubleOut(cx) + " " + pdfNumber.doubleOut(cy - ry) + " c\n"; + currentStream.write(str); + doDrawing(di); + } + + /** + * add an SVG rectangle to the current stream. + * If there are curved edges then these are rendered using bezier curves. + * + * @param x the x position of left edge + * @param y the y position of top edge + * @param w the width + * @param h the height + * @param rx the x radius curved edge + * @param ry the y radius curved edge + */ + protected void addRect(float x, float y, float w, float h, + float rx, float ry, DrawingInstruction di) { + PDFNumber pdfNumber = new PDFNumber(); + String str = ""; + if (rx == 0.0 && ry == 0.0) { + str = "" + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y) + " " + pdfNumber.doubleOut(w) + " " + pdfNumber.doubleOut(h) + " re\n"; + } else { + if (ry == 0.0) + ry = rx; + if (rx > w / 2.0f) + rx = w / 2.0f; + if (ry > h / 2.0f) + ry = h / 2.0f; + str = "" + pdfNumber.doubleOut(x + rx) + " " + pdfNumber.doubleOut(y) + " m\n"; + str += "" + pdfNumber.doubleOut(x + w - rx) + " " + pdfNumber.doubleOut(y) + " l\n"; + str += "" + pdfNumber.doubleOut(x + w - 19 * rx / 40) + " " + pdfNumber.doubleOut(y) + " " + + pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + 19 * ry / 40) + " " + + pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + ry) + " c\n"; + str += "" + pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + h - ry) + " l\n"; + str += "" + pdfNumber.doubleOut(x + w) + " " + pdfNumber.doubleOut(y + h - 19 * ry / 40) + " " + + pdfNumber.doubleOut(x + w - 19 * rx / 40) + " " + pdfNumber.doubleOut(y + h) + " " + + pdfNumber.doubleOut(x + w - rx) + " " + pdfNumber.doubleOut(y + h) + " c\n"; + str += "" + pdfNumber.doubleOut(x + rx) + " " + pdfNumber.doubleOut(y + h) + " l\n"; + str += "" + pdfNumber.doubleOut(x + 19 * rx / 40) + " " + pdfNumber.doubleOut(y + h) + " " + pdfNumber.doubleOut(x) + + " " + pdfNumber.doubleOut(y + h - 19 * ry / 40) + " " + pdfNumber.doubleOut(x) + " " + + pdfNumber.doubleOut(y + h - ry) + " c\n"; + str += "" + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y + ry) + " l\n"; + str += "" + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y + 19 * ry / 40) + " " + + pdfNumber.doubleOut(x + 19 * rx / 40) + " " + pdfNumber.doubleOut(y) + " " + pdfNumber.doubleOut(x + rx) + + " " + pdfNumber.doubleOut(y) + " c\n"; + } + currentStream.write(str); + doDrawing(di); + } + + /** + * Adds an SVG path to the current streem. + * An SVG path is made up of a list of drawing instructions that are rendered + * out in order. + * Arcs don't work. + */ + protected void addPath(Vector points, int posx, int posy, + DrawingInstruction di) { + PDFNumber pdfNumber = new PDFNumber(); + SVGPathSegImpl pathmoveto = null; + float lastx = 0; + float lasty = 0; + float lastmovex = 0; + float lastmovey = 0; + float[] cxs; + float tempx; + float tempy; + float lastcx = 0; + float lastcy = 0; + for (Enumeration e = points.elements(); e.hasMoreElements();) { + SVGPathSegImpl pc = (SVGPathSegImpl) e.nextElement(); + float[] vals = pc.getValues(); + switch (pc.getPathSegType()) { + case SVGPathSeg.PATHSEG_MOVETO_ABS: + pathmoveto = pc; + lastx = vals[0]; + lasty = vals[1]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " m\n"); + lastcx = 0; + lastcy = 0; + lastmovex = lastx; + lastmovey = lasty; + break; + case SVGPathSeg.PATHSEG_MOVETO_REL: + // the test cases seem to interprete this command differently + // it seems if there is an 'm' then the current path is closed + // then the point is move to a place relative to the point + // after doing the close + if (pathmoveto == null) { + lastx += vals[0]; + lasty += vals[1]; + pathmoveto = pc; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " m\n"); + } else { + lastx += vals[0]; + lasty += vals[1]; + pathmoveto = pc; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + } + lastmovex = lastx; + lastmovey = lasty; + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_LINETO_ABS: + lastx = vals[0]; + lasty = vals[1]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_LINETO_REL: + lastx += vals[0]; + lasty += vals[1]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: + lasty = vals[0]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: + lasty += vals[0]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: + lastx = vals[0]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: + lastx += vals[0]; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + lastcx = 0; + lastcy = 0; + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: + lastx = vals[4]; + lasty = vals[5]; + lastcx = vals[2]; + lastcy = vals[3]; + currentStream.write(pdfNumber.doubleOut(vals[0]) + " " + pdfNumber.doubleOut(vals[1]) + + " " + pdfNumber.doubleOut(vals[2]) + " " + pdfNumber.doubleOut(vals[3]) + " " + + pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " c\n"); + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: + currentStream.write(pdfNumber.doubleOut(vals[0] + lastx) + " " + + pdfNumber.doubleOut(vals[1] + lasty) + " " + + pdfNumber.doubleOut(vals[2] + lastx) + " " + + pdfNumber.doubleOut(vals[3] + lasty) + " " + + pdfNumber.doubleOut(vals[4] + lastx) + " " + + pdfNumber.doubleOut(vals[5] + lasty) + " c\n"); + lastcx = vals[2] + lastx; + lastcy = vals[3] + lasty; + lastx += vals[4]; + lasty += vals[5]; + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + if (lastcx == 0) { + lastcx = lastx; + } + if (lastcy == 0) { + lastcy = lasty; + } + lastcx = lastx + (lastx - lastcx); + lastcy = lasty + (lasty - lastcy); + lastx = vals[2]; + lasty = vals[3]; + currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + + pdfNumber.doubleOut(vals[0]) + " " + pdfNumber.doubleOut(vals[1]) + " " + + pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " c\n"); + lastcx = vals[0]; + lastcy = vals[1]; + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + if (lastcx == 0) { + lastcx = lastx; + } + if (lastcy == 0) { + lastcy = lasty; + } + lastcx = lastx + (lastx - lastcx); + lastcy = lasty + (lasty - lastcy); + currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + + pdfNumber.doubleOut(vals[0] + lastx) + " " + + pdfNumber.doubleOut(vals[1] + lasty) + " " + + pdfNumber.doubleOut(vals[2] + lastx) + " " + + pdfNumber.doubleOut(vals[3] + lasty) + " c\n"); + lastcx = (vals[0] + lastx); + lastcy = (vals[1] + lasty); + lastx += vals[2]; + lasty += vals[3]; + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: + if (lastcx == 0) { + lastcx = lastx; + } + if (lastcy == 0) { + lastcy = lasty; + } + tempx = lastx; + tempy = lasty; + lastx = vals[2]; + lasty = vals[3]; + currentStream.write(pdfNumber.doubleOut(vals[0]) + " " + pdfNumber.doubleOut(vals[1]) + " " + + pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " y\n"); + cxs = calculateLastControl(tempx, tempy, lastx, lasty, -tempx + vals[0], -tempy + vals[1]); + lastcx = cxs[0]; + lastcy = cxs[1]; + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: + if (lastcx == 0) { + lastcx = lastx; + } + if (lastcy == 0) { + lastcy = lasty; + } + currentStream.write(pdfNumber.doubleOut(vals[0] + lastx) + " " + pdfNumber.doubleOut(vals[1] + lasty) + " " + + pdfNumber.doubleOut(vals[2] + lastx) + " " + + pdfNumber.doubleOut(vals[3] + lasty) + " y\n"); + cxs = calculateLastControl(lastx, lasty, lastx + vals[2], lasty + vals[3], vals[0], vals[1]); + lastcx = cxs[0]; + lastcy = cxs[1]; + lastx += vals[2]; + lasty += vals[3]; + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + if (lastcx == 0) { + lastcx = lastx; + } + if (lastcy == 0) { + lastcy = lasty; + } + tempx = lastx; + tempy = lasty; + lastcx = lastx + (lastx - lastcx); + lastcy = lasty + (lasty - lastcy); + lastx = vals[0]; + lasty = vals[1]; + currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + + pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " y\n"); + cxs = calculateLastControl(tempx, tempy, lastx, lasty, -tempx + lastcx, -tempy + lastcy); + lastcx = cxs[0]; + lastcy = cxs[1]; + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + if (lastcx == 0) { + lastcx = lastx; + } + if (lastcy == 0) { + lastcy = lasty; + } + lastcx = lastx + (lastx - lastcx); + lastcy = lasty + (lasty - lastcy); + currentStream.write(pdfNumber.doubleOut(lastcx) + " " + pdfNumber.doubleOut(lastcy) + " " + + pdfNumber.doubleOut(vals[0] + lastx) + " " + + pdfNumber.doubleOut(vals[1] + lasty) + " y\n"); + cxs = calculateLastControl(lastx, lasty, lastx + vals[0], lasty + vals[1], -lastx + lastcx, -lasty + lastcy); + lastcx = cxs[0]; + lastcy = cxs[1]; + lastx += vals[0]; + lasty += vals[1]; + break; + // get angle between the two points + // then get angle of points to centre (ie. both points are on the + // apogee and perigee of the ellipse) + // then work out the direction from flags + case SVGPathSeg.PATHSEG_ARC_ABS: + { /* double rx = vals[0]; - double ry = vals[1]; - double theta = vals[2]; - boolean largearcflag = (vals[3] == 1.0); - boolean sweepflag = (vals[4] == 1.0); - - double angle = Math.atan((vals[6] - lasty) / - (vals[5] - lastx)); - double relangle = Math.acos(rx / - Math.sqrt((vals[6] - lasty) * - (vals[6] - lasty) + - (vals[5] - lastx) * (vals[5] - lastx))); - double absangle = angle + relangle; - // change sign depending on flags - double contrx1; - double contry1; - double contrx2; - double contry2; - if (largearcflag) { - if (sweepflag) { - contrx1 = lastx - rx * Math.cos(absangle); - contry1 = lasty + rx * Math.sin(absangle); - contrx2 = vals[5] + ry * Math.cos(absangle); - contry2 = vals[6] + ry * Math.sin(absangle); - } else { - contrx1 = lastx - rx * Math.cos(absangle); - contry1 = lasty - rx * Math.sin(absangle); - contrx2 = vals[5] + ry * Math.cos(absangle); - contry2 = vals[6] - ry * Math.sin(absangle); - } - } else { - if (sweepflag) { - contrx1 = lastx + rx * Math.cos(absangle); - contry1 = lasty + rx * Math.sin(absangle); - contrx2 = contrx1; - contry2 = contry1; - } else { - contrx1 = lastx + ry * Math.cos(absangle); - contry1 = lasty - ry * Math.sin(absangle); - contrx2 = contrx1; - contry2 = contry1; - } - } - - double cx = lastx; - double cy = lasty; - currentStream.write(pdfNumber.doubleOut(contrx1) + " " + pdfNumber.doubleOut(contry1) + - " " + pdfNumber.doubleOut(contrx2) + " " + pdfNumber.doubleOut(contry2) + " " + - pdfNumber.doubleOut(vals[5]) + " " + pdfNumber.doubleOut(vals[6]) + " c\n"); - lastcx = 0; //?? - lastcy = 0; //?? - lastx = vals[5]; - lasty = vals[6];*/ - } - break; - case SVGPathSeg.PATHSEG_ARC_REL: - { + double ry = vals[1]; + double theta = vals[2]; + boolean largearcflag = (vals[3] == 1.0); + boolean sweepflag = (vals[4] == 1.0); + + double angle = Math.atan((vals[6] - lasty) / + (vals[5] - lastx)); + double relangle = Math.acos(rx / + Math.sqrt((vals[6] - lasty) * + (vals[6] - lasty) + + (vals[5] - lastx) * (vals[5] - lastx))); + double absangle = angle + relangle; + // change sign depending on flags + double contrx1; + double contry1; + double contrx2; + double contry2; + if (largearcflag) { + if (sweepflag) { + contrx1 = lastx - rx * Math.cos(absangle); + contry1 = lasty + rx * Math.sin(absangle); + contrx2 = vals[5] + ry * Math.cos(absangle); + contry2 = vals[6] + ry * Math.sin(absangle); + } else { + contrx1 = lastx - rx * Math.cos(absangle); + contry1 = lasty - rx * Math.sin(absangle); + contrx2 = vals[5] + ry * Math.cos(absangle); + contry2 = vals[6] - ry * Math.sin(absangle); + } + } else { + if (sweepflag) { + contrx1 = lastx + rx * Math.cos(absangle); + contry1 = lasty + rx * Math.sin(absangle); + contrx2 = contrx1; + contry2 = contry1; + } else { + contrx1 = lastx + ry * Math.cos(absangle); + contry1 = lasty - ry * Math.sin(absangle); + contrx2 = contrx1; + contry2 = contry1; + } + } + + double cx = lastx; + double cy = lasty; + currentStream.write(pdfNumber.doubleOut(contrx1) + " " + pdfNumber.doubleOut(contry1) + + " " + pdfNumber.doubleOut(contrx2) + " " + pdfNumber.doubleOut(contry2) + " " + + pdfNumber.doubleOut(vals[5]) + " " + pdfNumber.doubleOut(vals[6]) + " c\n"); + lastcx = 0; //?? + lastcy = 0; //?? + lastx = vals[5]; + lasty = vals[6];*/ + } + break; + case SVGPathSeg.PATHSEG_ARC_REL: + { /* double rx = vals[0]; - double ry = vals[1]; - double theta = vals[2]; - boolean largearcflag = (vals[3] == 1.0); - boolean sweepflag = (vals[4] == 1.0); - - double angle = Math.atan(vals[6] / vals[5]); - double relangle = Math.atan(ry / rx); - // System.out.println((theta * Math.PI / 180f) + ":" + relangle + ":" + largearcflag + ":" + sweepflag); - double absangle = (theta * Math.PI / 180f);//angle + relangle; - // change sign depending on flags - double contrx1; - double contry1; - double contrx2; - double contry2; - if (largearcflag) { - // in a large arc we need to do at least 2 and a bit - // segments or curves. - if (sweepflag) { - contrx1 = lastx + rx * Math.cos(absangle); - contry1 = lasty + rx * Math.sin(absangle); - contrx2 = lastx + vals[5] + - ry * Math.cos(absangle); - contry2 = lasty + vals[6] - - ry * Math.sin(absangle); - } else { - contrx1 = lastx + rx * Math.sin(absangle); - contry1 = lasty + rx * Math.cos(absangle); - contrx2 = lastx + vals[5] + - ry * Math.cos(absangle); - contry2 = lasty + vals[6] + - ry * Math.sin(absangle); - } - } else { - // only need at most two segments - if (sweepflag) { - contrx1 = lastx + rx * Math.cos(absangle); - contry1 = lasty - rx * Math.sin(absangle); - contrx2 = contrx1; - contry2 = contry1; - } else { - contrx1 = lastx - ry * Math.cos(absangle); - contry1 = lasty + ry * Math.sin(absangle); - contrx2 = contrx1; - contry2 = contry1; - } - } - //System.out.println(contrx1 + ":" + contry1 + ":" + contrx2 + ":" + contry2); - - double cx = lastx; - double cy = lasty; - currentStream.write(pdfNumber.doubleOut(contrx1) + " " + pdfNumber.doubleOut(contry1) + - " " + pdfNumber.doubleOut(contrx2) + " " + pdfNumber.doubleOut(contry2) + " " + - pdfNumber.doubleOut(vals[5] + lastx) + " " + - pdfNumber.doubleOut(vals[6] + lasty) + " c\n"); - - lastcx = 0; //?? - lastcy = 0; //?? - lastx += vals[5]; - lasty += vals[6];*/ - } - break; - case SVGPathSeg.PATHSEG_CLOSEPATH: - currentStream.write("h\n"); - pathmoveto = null; - lastx = lastmovex; - lasty = lastmovey; - break; - } - } - doDrawing(di); - } - - /** - * Calculate the last control point for a bezier curve. - * This is used to find the last control point for a curve where - * only the first control point is specified. - * The control point is a reflection of the first control point - * which results in an even smooth curve. The curve is symmetrical. - */ - protected float[] calculateLastControl(float x1, float y1, float x2, float y2, float relx, float rely) - { - float vals[] = new float[2]; - relx = -relx; - rely = -rely; - float dist = (float)Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); - float costheta = (float)(x2 - x1) / dist; - float sinetheta = (float)(y2 - y1) / dist; - float temp = relx; - relx = relx * costheta + rely * sinetheta; - rely = -temp * sinetheta + rely * costheta; - relx = -relx; - temp = relx; - relx = relx * costheta - rely * sinetheta; - rely = temp * sinetheta + rely * costheta; - vals[0] = x2 - relx; - vals[1] = y2 - rely; - return vals; - } - - /** - * Adds an SVG polyline or polygon. - * A polygon is merely a closed polyline. - * This is made up from a set of points that straight lines are drawn between. - */ - protected void addPolyline(Vector points, DrawingInstruction di, - boolean close) { - PDFNumber pdfNumber = new PDFNumber(); - PathPoint pc; - float lastx = 0; - float lasty = 0; - Enumeration e = points.elements(); - if (e.hasMoreElements()) { - pc = (PathPoint) e.nextElement(); - lastx = pc.x; - lasty = pc.y; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " m\n"); - } - while (e.hasMoreElements()) { - pc = (PathPoint) e.nextElement(); - lastx = pc.x; - lasty = pc.y; - currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); - } - if (close) - currentStream.write("h\n"); - doDrawing(di); - } - - /** - * Writes the drawing instruction out to the current stream - * depending on what type of drawing is required. - */ - protected void doDrawing(DrawingInstruction di) { - if (di == null) { - currentStream.write("S\n"); - } else { - if (di.fill) { - if (di.stroke) { - if (!di.nonzero) - currentStream.write("B*\n"); - else - currentStream.write("B\n"); - } else { - if (!di.nonzero) - currentStream.write("f*\n"); - else - currentStream.write("f\n"); - } - } else { - // if(di.stroke) - currentStream.write("S\n"); - } - } - } - - /** - * Renders an svg image to the current stream. - * This uses the FopImageFactory to load the image and then renders it. - */ - public void renderImage(String href, float x, float y, float width, - float height) { - try { - if (href.indexOf(":") == -1) { - href = "file:" + href; - } - FopImage img = FopImageFactory.Make(href); - PDFNumber pdfNumber = new PDFNumber(); - if (img instanceof SVGImage) { - SVGSVGElement svg = - ((SVGImage) img).getSVGDocument().getRootElement(); - currentStream.write("q\n" + pdfNumber.doubleOut(width / - svg.getWidth().getBaseVal().getValue()) + " 0 0 " + - pdfNumber.doubleOut(height / - svg.getHeight().getBaseVal().getValue()) + " 0 0 cm\n"); - renderSVG(svg, (int) x * 1000, (int) y * 1000); - currentStream.write("Q\n"); - // renderSVG(svg); - } else if (img != null) { - int xObjectNum = this.pdfDoc.addImage(img); - currentStream.write("q\n1 0 0 -1 0 " + - pdfNumber.doubleOut(2 * y + height) + " cm\n" + pdfNumber.doubleOut(width) + " 0 0 " + - pdfNumber.doubleOut(height) + " " + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y) + " cm\n" + "/Im" + - xObjectNum + " Do\nQ\n"); - // img.close(); - } - } catch (Exception e) { - MessageHandler.errorln("could not add image to SVG: " + href); - } - } - - /** - * A symbol has a viewbox and preserve aspect ratio. - */ - protected void renderSymbol(SVGSymbolElement symbol, int x, int y) { - NodeList nl = symbol.getChildNodes(); - for (int count = 0; count < nl.getLength(); count++) { - Node n = nl.item(count); - if (n instanceof SVGElement) { - renderElement((SVGElement) n, x, y); - } - } - } - - /** - * Handles the construction of an SVG gradient. - * This gets the gradient element and creates the pdf info - * in the pdf document. - * The type of gradient is determined by what class the gradient element is. - */ - protected void handleGradient(String sp, DrawingInstruction di, - boolean fill, SVGElement area) { - // should be a url to a gradient - String url = (String) sp; - if (url.startsWith("url(")) { - String address; - int b1 = url.indexOf("("); - int b2 = url.indexOf(")"); - address = url.substring(b1 + 1, b2); - SVGElement gi = null; - gi = locateDef(address, area); - if (gi instanceof SVGLinearGradientElement) { - SVGLinearGradientElement linear = - (SVGLinearGradientElement) gi; - handleLinearGradient(linear, di, fill, area); - } else if (gi instanceof SVGRadialGradientElement) { - SVGRadialGradientElement radial = - (SVGRadialGradientElement) gi; - handleRadialGradient(radial, di, fill, area); - } else if (gi instanceof SVGPatternElement) { - SVGPatternElement pattern = (SVGPatternElement) gi; - handlePattern(pattern, di, fill, area); - } else { - MessageHandler.errorln("WARNING Invalid fill reference :" + - gi + ":" + address); - } - } - } - - protected void handlePattern(SVGPatternElement pattern, - DrawingInstruction di, boolean fill, SVGElement area) { - SVGAnimatedLength x, y, width, height; - short pattUnits = SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN; - NodeList stops = null; - x = pattern.getX(); - y = pattern.getY(); - width = pattern.getWidth(); - height = pattern.getHeight(); - NodeList nl = pattern.getChildNodes(); - SVGPatternElement ref = (SVGPatternElement) locateDef( - pattern.getHref().getBaseVal(), pattern); - while (ref != null) { - if (x == null) { - x = ref.getX(); - pattUnits = ref.getPatternUnits().getBaseVal(); - } - if (y == null) { - y = ref.getY(); - } - if (width == null) { - width = ref.getWidth(); - } - if (height == null) { - height = ref.getHeight(); - } - if (nl.getLength() == 0) { - nl = ref.getChildNodes(); - } - ref = (SVGPatternElement) locateDef( - ref.getHref().getBaseVal(), ref); - } - if (x == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); - x = new SVGAnimatedLengthImpl(length); - } - if (y == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); - y = new SVGAnimatedLengthImpl(length); - } - if (width == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); - width = new SVGAnimatedLengthImpl(length); - } - if (height == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); - height = new SVGAnimatedLengthImpl(length); - } - - StringWriter realStream = currentStream; - currentStream = new StringWriter(); - - currentStream.write("q\n"); - // this makes the pattern the right way up, since it is outside the original - // transform around the whole svg document - currentStream.write("1 0 0 -1 0 " + - height.getBaseVal().getValue() + " cm\n"); - for (int count = 0; count < nl.getLength(); count++) { - Node n = nl.item(count); - if (n instanceof SVGElement) { - renderElement((SVGElement) n, 0, 0); - } - } - currentStream.write("Q\n"); - - double xval = x.getBaseVal().getValue() + currentXPosition / 1000f; - double yval = -y.getBaseVal().getValue() + currentYPosition / 1000f; - if (area instanceof GraphicElement) { - SVGRect bbox = ((GraphicElement) area).getBBox(); - if (bbox != null) { - // xval += bbox.getX(); - // yval -= bbox.getY(); - } - } - double widthval = width.getBaseVal().getValue(); - double heightval = height.getBaseVal().getValue(); - Vector bbox = new Vector(); - bbox.addElement(new Double(0)); - bbox.addElement(new Double(0)); - bbox.addElement(new Double(widthval)); - bbox.addElement(new Double(heightval)); - Vector translate = new Vector(); - // combine with pattern transform - translate.addElement(new Double(1)); - translate.addElement(new Double(0)); - translate.addElement(new Double(0)); - translate.addElement(new Double(1)); - translate.addElement(new Double(xval)); - translate.addElement(new Double(yval)); - // need to handle PDFResources - PDFPattern myPat = - this.pdfDoc.makePattern(1, null, 1, 1, bbox, widthval, - heightval, translate, null, currentStream.getBuffer()); - - currentStream = realStream; - currentStream.write(myPat.getColorSpaceOut(fill)); - if (fill) - di.fill = true; - else - di.stroke = true; - } - - protected void handleLinearGradient( - SVGLinearGradientElement linear, DrawingInstruction di, - boolean fill, SVGElement area) { - // first get all the gradient values - // if values not present follow the href - // the gradient units will be where the vals are specified - // the spread method will be where there are stop elements - SVGAnimatedLength ax1, ax2, ay1, ay2; - short spread = SVGGradientElement.SVG_SPREADMETHOD_UNKNOWN; - short gradUnits = SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN; - NodeList stops = null; - ax1 = linear.getX1(); - ax2 = linear.getX2(); - ay1 = linear.getY1(); - ay2 = linear.getY2(); - stops = linear.getChildNodes(); - SVGLinearGradientElement ref = (SVGLinearGradientElement) locateDef( - linear.getHref().getBaseVal(), linear); - while (ref != null) { - if (ax1 == null) { - ax1 = ref.getX1(); - gradUnits = ref.getGradientUnits().getBaseVal(); - } - if (ax2 == null) { - ax2 = ref.getX2(); - } - if (ay1 == null) { - ay1 = ref.getY1(); - } - if (ay2 == null) { - ay2 = ref.getY2(); - } - if (stops.getLength() == 0) { - stops = ref.getChildNodes(); - } - ref = (SVGLinearGradientElement) locateDef( - ref.getHref().getBaseVal(), ref); - } - if (ax1 == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); - ax1 = new SVGAnimatedLengthImpl(length); - } - if (ax2 == null) { - // if x2 is not specified then it should be 100% - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); - ax2 = new SVGAnimatedLengthImpl(length); - } - if (ay1 == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); - ay1 = new SVGAnimatedLengthImpl(length); - } - if (ay2 == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); - ay2 = new SVGAnimatedLengthImpl(length); - } - SVGAnimatedTransformList an = linear.getGradientTransform(); - SVGMatrix transform = null; - if(an != null) - transform = an.getBaseVal().consolidate().getMatrix(); - Vector theCoords = null; - if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN) - gradUnits = linear.getGradientUnits().getBaseVal(); - // spread: pad (normal), reflect, repeat - spread = linear.getSpreadMethod().getBaseVal(); - if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE) { - if (area instanceof SVGTransformable) { - SVGTransformable tf = (SVGTransformable) area; - double x1, y1, x2, y2; - x1 = ax1.getBaseVal().getValue(); - y1 = -ay1.getBaseVal().getValue(); - x2 = ax2.getBaseVal().getValue(); - y2 = -ay2.getBaseVal().getValue(); - SVGMatrix matrix = tf.getScreenCTM(); - if(transform != null) - matrix = matrix.multiply(transform); - double oldx = x1; - x1 = matrix.getA() * x1 + matrix.getC() * y1 + - matrix.getE(); - y1 = matrix.getB() * oldx + matrix.getD() * y1 - - matrix.getF(); - oldx = x2; - x2 = matrix.getA() * x2 + matrix.getC() * y2 + - matrix.getE(); - y2 = matrix.getB() * oldx + matrix.getD() * y2 - - matrix.getF(); - theCoords = new Vector(); - if (spread == SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { - } else if (spread == - SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + x1)); - theCoords.addElement( - new Double(currentYPosition / 1000f + y1)); - theCoords.addElement( - new Double(currentXPosition / 1000f + x2)); - theCoords.addElement( - new Double(currentYPosition / 1000f + y2)); - } - } - } else if (area instanceof GraphicElement) { - SVGRect rect = ((GraphicElement) area).getBBox(); - if (rect != null) { - theCoords = new Vector(); - SVGLength val; - val = ax1.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentXPosition / 1000f + - rect.getX() + - val.getValue() * rect.getWidth())); - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + - val.getValue())); - } - val = ay1.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentYPosition / 1000f - - rect.getY() - - val.getValue() * rect.getHeight())); - } else { - theCoords.addElement( - new Double(currentYPosition / 1000f - - val.getValue())); - } - val = ax2.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentXPosition / 1000f + - rect.getX() + - val.getValue() * rect.getWidth())); - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + - val.getValue())); - } - val = ay2.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentYPosition / 1000f - - rect.getY() - - val.getValue() * rect.getHeight())); - } else { - theCoords.addElement( - new Double(currentYPosition / 1000f - - val.getValue())); - } - } - } - if (theCoords == null) { - theCoords = new Vector(); - theCoords.addElement( new Double(currentXPosition / 1000f + - ax1.getBaseVal().getValue())); - theCoords.addElement( new Double(currentYPosition / 1000f - - ay1.getBaseVal().getValue())); - theCoords.addElement( new Double(currentXPosition / 1000f + - ax2.getBaseVal().getValue())); - theCoords.addElement( new Double(currentYPosition / 1000f - - ay2.getBaseVal().getValue())); - } - - Vector theExtend = new Vector(); - theExtend.addElement(new Boolean(true)); - theExtend.addElement(new Boolean(true)); - - Vector theDomain = new Vector(); - theDomain.addElement(new Double(0)); - theDomain.addElement(new Double(1)); - - Vector theEncode = new Vector(); - theEncode.addElement(new Double(0)); - theEncode.addElement(new Double(1)); - theEncode.addElement(new Double(0)); - theEncode.addElement(new Double(1)); - - Vector theBounds = new Vector(); - theBounds.addElement(new Double(0)); - theBounds.addElement(new Double(1)); - - Vector theFunctions = new Vector(); - - NodeList nl = stops; - Vector someColors = new Vector(); - float lastoffset = 0; - Vector lastVector = null; - SVGStopElementImpl stop; - if (nl.getLength() == 0) { - // the color should be "none" - if (fill) - di.fill = false; - else - di.stroke = false; - return; - } else if (nl.getLength() == 1) { - stop = (SVGStopElementImpl) nl.item(0); - CSSValue cv = stop.getPresentationAttribute("stop-color"); - if (cv == null) { - // maybe using color - cv = stop.getPresentationAttribute("color"); - } - if (cv == null) { - // problems - MessageHandler.errorln("no stop-color or color in stop element"); - return; - } - PDFColor color = new PDFColor(0, 0, 0); - if (cv != null && - cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) cv).getPrimitiveType() == - CSSPrimitiveValue.CSS_RGBCOLOR) { - RGBColor col = - ((CSSPrimitiveValue) cv).getRGBColorValue(); - CSSPrimitiveValue val; - val = col.getRed(); - float red = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getGreen(); - float green = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getBlue(); - float blue = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - color = new PDFColor(red, green, blue); - } - } - currentStream.write(color.getColorSpaceOut(fill)); - if (fill) - di.fill = true; - else - di.stroke = true; - return; - } - for (int count = 0; count < nl.getLength(); count++) { - stop = (SVGStopElementImpl) nl.item(count); - CSSValue cv = stop.getPresentationAttribute("stop-color"); - if (cv == null) { - // maybe using color - cv = stop.getPresentationAttribute("color"); - } - if (cv == null) { - // problems - MessageHandler.errorln("no stop-color or color in stop element"); - continue; - } - PDFColor color = new PDFColor(0, 0, 0); - if (cv != null && - cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) cv).getPrimitiveType() == - CSSPrimitiveValue.CSS_RGBCOLOR) { - RGBColor col = - ((CSSPrimitiveValue) cv).getRGBColorValue(); - CSSPrimitiveValue val; - val = col.getRed(); - float red = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getGreen(); - float green = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getBlue(); - float blue = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - color = new PDFColor(red, green, blue); - currentColour = color; - } - } - float offset = stop.getOffset().getBaseVal(); - Vector colVector = color.getVector(); - // create bounds from last to offset - if (lastVector != null) { - Vector theCzero = lastVector; - Vector theCone = colVector; - PDFFunction myfunc = - this.pdfDoc.makeFunction(2, theDomain, null, - theCzero, theCone, 1.0); - theFunctions.addElement(myfunc); - } - lastoffset = offset; - lastVector = colVector; - someColors.addElement(color); - } - ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); - /* PDFFunction myfunky = this.pdfDoc.makeFunction(3, - theDomain, null, - theFunctions, null, - theEncode); - PDFShading myShad = null; - myShad = this.pdfDoc.makeShading( - 2, aColorSpace, - null, null, false, - theCoords, null, myfunky,theExtend); - PDFPattern myPat = this.pdfDoc.makePattern(2, myShad, null, null, null);*/ - PDFPattern myPat = this.pdfDoc.createGradient(false, aColorSpace, - someColors, null, theCoords); - currentStream.write(myPat.getColorSpaceOut(fill)); - if (fill) - di.fill = true; - else - di.stroke = true; - } - - protected void handleRadialGradient( - SVGRadialGradientElement radial, DrawingInstruction di, - boolean fill, SVGElement area) { - // first get all the gradient values - // if values not present follow the href - // the gradient units will be where the vals are specified - SVGAnimatedLength acx, acy, ar, afx, afy; - short gradUnits = radial.getGradientUnits().getBaseVal(); - NodeList stops = null; - acx = radial.getCx(); - acy = radial.getCy(); - ar = radial.getR(); - afx = radial.getFx(); - afy = radial.getFy(); - stops = radial.getChildNodes(); - SVGRadialGradientElement ref = (SVGRadialGradientElement) locateDef( - radial.getHref().getBaseVal(), radial); - while (ref != null) { - if (acx == null) { - acx = ref.getCx(); - gradUnits = ref.getGradientUnits().getBaseVal(); - } - if (acy == null) { - acy = ref.getCy(); - } - if (ar == null) { - ar = ref.getR(); - } - if (afx == null) { - afx = ref.getFx(); - } - if (afy == null) { - afy = ref.getFy(); - } - if (stops.getLength() == 0) { - stops = ref.getChildNodes(); - } - ref = (SVGRadialGradientElement) locateDef( - ref.getHref().getBaseVal(), ref); - } - if (acx == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); - acx = new SVGAnimatedLengthImpl(length); - } - if (acy == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); - acy = new SVGAnimatedLengthImpl(length); - } - if (ar == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); - ar = new SVGAnimatedLengthImpl(length); - } - if (afx == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); - afx = new SVGAnimatedLengthImpl(length); - } - if (afy == null) { - SVGLength length = new SVGLengthImpl(); - length.newValueSpecifiedUnits( - SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); - afy = new SVGAnimatedLengthImpl(length); - } - ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); - org.w3c.dom.NodeList nl = stops; - SVGStopElementImpl stop; - if (nl.getLength() == 0) { - // the color should be "none" - if (fill) - di.fill = false; - else - di.stroke = false; - return; - } else if (nl.getLength() == 1) { - stop = (SVGStopElementImpl) nl.item(0); - CSSValue cv = stop.getPresentationAttribute("stop-color"); - if (cv == null) { - // maybe using color - cv = stop.getPresentationAttribute("color"); - } - if (cv == null) { - // problems - MessageHandler.errorln("no stop-color or color in stop element"); - return; - } - PDFColor color = new PDFColor(0, 0, 0); - if (cv != null && - cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) cv).getPrimitiveType() == - CSSPrimitiveValue.CSS_RGBCOLOR) { - RGBColor col = - ((CSSPrimitiveValue) cv).getRGBColorValue(); - CSSPrimitiveValue val; - val = col.getRed(); - float red = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getGreen(); - float green = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getBlue(); - float blue = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - color = new PDFColor(red, green, blue); - } - } - currentStream.write(color.getColorSpaceOut(fill)); - if (fill) - di.fill = true; - else - di.stroke = true; - return; - } - Hashtable table = null; - Vector someColors = new Vector(); - Vector theCoords = null; - Vector theBounds = new Vector(); - // the coords should be relative to the current object - // check value types, eg. % - if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE) { - if (area instanceof SVGTransformable) { - SVGTransformable tf = (SVGTransformable) area; - double x1, y1, x2, y2; - x1 = acx.getBaseVal().getValue(); - y1 = -acy.getBaseVal().getValue(); - x2 = afx.getBaseVal().getValue(); - y2 = -afy.getBaseVal().getValue(); - SVGMatrix matrix = tf.getScreenCTM(); - double oldx = x1; - x1 = matrix.getA() * x1 + matrix.getB() * y1 + - matrix.getE(); - y1 = matrix.getC() * oldx + matrix.getD() * y1 + - matrix.getF(); - oldx = x2; - x2 = matrix.getA() * x2 + matrix.getB() * y2 + - matrix.getE(); - y2 = matrix.getC() * oldx + matrix.getD() * y2 + - matrix.getF(); - theCoords = new Vector(); - // if(spread == SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { - // } else if(spread== SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { - // } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + x1)); - // the y val needs to be adjust by 2 * R * rotation - // depending on if this value is from an x or y coord - // before transformation - theCoords.addElement( - new Double(currentYPosition / 1000f - y1 + - (matrix.getC() - matrix.getD()) * 2 * - ar.getBaseVal().getValue())); - theCoords.addElement(new Double(0)); - theCoords.addElement( - new Double(currentXPosition / 1000f + x2)); - theCoords.addElement( - new Double(currentYPosition / 1000f - y2 + - (matrix.getC() - matrix.getD()) * 2 * - ar.getBaseVal().getValue())); - theCoords.addElement( - new Double(ar.getBaseVal().getValue())); - // } - } - } else if (gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && - area instanceof GraphicElement) { - SVGRect rect = ((GraphicElement) area).getBBox(); - if (rect != null) { - theCoords = new Vector(); - SVGLength val; - val = acx.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentXPosition / 1000f + - rect.getX() + - val.getValue() * rect.getWidth())); - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + - val.getValue())); - } - val = acy.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentYPosition / 1000f - - rect.getY() - - val.getValue() * rect.getHeight())); - } else { - theCoords.addElement( - new Double(currentYPosition / 1000f - - val.getValue())); - } - theCoords.addElement(new Double(0)); - val = afx.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentXPosition / 1000f + - rect.getX() + - val.getValue() * rect.getWidth())); - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + - val.getValue())); - } - val = afy.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentYPosition / 1000f - - rect.getY() - - val.getValue() * rect.getHeight())); - } else { - theCoords.addElement( - new Double(currentYPosition / 1000f - - val.getValue())); - } - val = ar.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(val.getValue() * rect.getHeight())); - } else { - theCoords.addElement(new Double(val.getValue())); - } - } - } - if (theCoords == null) { - // percentage values are expressed according to the viewport. - SVGElement vp = - ((GraphicElement) area).getNearestViewportElement(); - if (area instanceof GraphicElement) { - SVGRect rect = ((GraphicElement) area).getBBox(); - if (rect != null) { - theCoords = new Vector(); - SVGLength val = acx.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || - gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentXPosition / 1000f + - rect.getX() + - val.getValue() * rect.getWidth())); - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + - val.getValue())); - } - val = acy.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || - gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentYPosition / 1000f - - rect.getY() - - val.getValue() * rect.getHeight())); - } else { - theCoords.addElement( - new Double(currentYPosition / 1000f - - val.getValue())); - } - theCoords.addElement(new Double(0)); - val = afx.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || - gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentXPosition / 1000f + - rect.getX() + - val.getValue() * rect.getWidth())); - } else { - theCoords.addElement( - new Double(currentXPosition / 1000f + - val.getValue())); - } - val = afy.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || - gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( - new Double(currentYPosition / 1000f - - rect.getY() - - val.getValue() * rect.getHeight())); - } else { - theCoords.addElement( - new Double(currentYPosition / 1000f - - val.getValue())); - } - val = ar.getBaseVal(); - if (val.getUnitType() == - SVGLength.SVG_LENGTHTYPE_PERCENTAGE || - gradUnits == - SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { - theCoords.addElement( new Double(val.getValue() * - rect.getHeight())); - } else { - theCoords.addElement(new Double(val.getValue())); - } - } - } - } - if (theCoords == null) { - theCoords = new Vector(); - theCoords.addElement( new Double(currentXPosition / 1000f + - acx.getBaseVal().getValue())); - theCoords.addElement( new Double(currentYPosition / 1000f - - acy.getBaseVal().getValue())); - theCoords.addElement(new Double(0)); - theCoords.addElement( new Double(currentXPosition / 1000f + - afx.getBaseVal().getValue())); // Fx - theCoords.addElement( - new Double(currentYPosition / 1000f - - afy.getBaseVal().getValue())); // Fy - theCoords.addElement( - new Double(ar.getBaseVal().getValue())); - } - float lastoffset = 0; - for (int count = 0; count < nl.getLength(); count++) { - stop = (SVGStopElementImpl) nl.item(count); - CSSValue cv = stop.getPresentationAttribute("stop-color"); - if (cv == null) { - // maybe using color - cv = stop.getPresentationAttribute("color"); - } - if (cv == null) { - // problems - MessageHandler.errorln("no stop-color or color in stop element"); - continue; - } - PDFColor color = new PDFColor(0, 0, 0); - if (cv != null && - cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) cv).getPrimitiveType() == - CSSPrimitiveValue.CSS_RGBCOLOR) { - RGBColor col = - ((CSSPrimitiveValue) cv).getRGBColorValue(); - CSSPrimitiveValue val; - val = col.getRed(); - float red = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getGreen(); - float green = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getBlue(); - float blue = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - color = new PDFColor(red, green, blue); - } - } - float offset = stop.getOffset().getBaseVal(); - // create bounds from last to offset - lastoffset = offset; - someColors.addElement(color); - } - PDFPattern myPat = this.pdfDoc.createGradient(true, aColorSpace, - someColors, theBounds, theCoords); - - currentStream.write(myPat.getColorSpaceOut(fill)); - if (fill) - di.fill = true; - else - di.stroke = true; - } - - /* - * This sets up the style for drawing objects. - * Should only set style for elements that have changes. - * - */ - // need mask drawing - class DrawingInstruction { - boolean stroke = false; - boolean nonzero = false; // non-zero fill rule "f*", "B*" operator - boolean fill = false; - int linecap = 0; // butt - int linejoin = 0; // miter - int miterwidth = 8; - } - protected DrawingInstruction applyStyle(SVGElement area, - SVGStylable style) { - DrawingInstruction di = new DrawingInstruction(); - CSSValue sp; - sp = style.getPresentationAttribute("fill"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_RGBCOLOR) { - RGBColor col = - ((CSSPrimitiveValue) sp).getRGBColorValue(); - CSSPrimitiveValue val; - val = col.getRed(); - float red = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getGreen(); - float green = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getBlue(); - float blue = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - PDFColor fillColour = new PDFColor(red, green, blue); - currentColour = fillColour; - currentStream.write(fillColour.getColorSpaceOut(true)); - di.fill = true; - } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_URI) { - // gradient - String str = ((CSSPrimitiveValue) sp).getCssText(); - handleGradient(str, di, true, area); - } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - String str = ((CSSPrimitiveValue) sp).getCssText(); - if (str.equals("none")) { - di.fill = false; - } else if (str.equals("currentColor")) { - currentStream.write( - currentColour.getColorSpaceOut(true)); - di.fill = true; - // } else { - // handleGradient(str, true, area); - } - } - } - } else { - PDFColor fillColour = new PDFColor(0, 0, 0); - currentStream.write(fillColour.getColorSpaceOut(true)); - } - sp = style.getPresentationAttribute("fill-rule"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - if (sp.getCssText().equals("nonzero")) { - di.nonzero = true; - } - } - } - } else { - } - sp = style.getPresentationAttribute("stroke"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_RGBCOLOR) { - RGBColor col = - ((CSSPrimitiveValue) sp).getRGBColorValue(); - CSSPrimitiveValue val; - val = col.getRed(); - float red = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getGreen(); - float green = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - val = col.getBlue(); - float blue = val.getFloatValue( - CSSPrimitiveValue.CSS_NUMBER); - PDFColor fillColour = new PDFColor(red, green, blue); - currentStream.write( - fillColour.getColorSpaceOut(false)); - di.stroke = true; - } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_URI) { - // gradient - String str = ((CSSPrimitiveValue) sp).getCssText(); - handleGradient(str, di, false, area); - } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - String str = ((CSSPrimitiveValue) sp).getCssText(); - if (str.equals("none")) { - di.stroke = false; - // } else { - // handleGradient(str, false, area); - } - } - } - } else { - PDFColor fillColour = new PDFColor(0, 0, 0); - currentStream.write(fillColour.getColorSpaceOut(false)); - } - sp = style.getPresentationAttribute("stroke-linecap"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - String str = sp.getCssText(); - // butt, round ,square - if (str.equals("butt")) { - currentStream.write(0 + " J\n"); - } else if (str.equals("round")) { - currentStream.write(1 + " J\n"); - } else if (str.equals("square")) { - currentStream.write(2 + " J\n"); - } - } - } - } else { - } - sp = style.getPresentationAttribute("stroke-linejoin"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - String str = sp.getCssText(); - if (str.equals("miter")) { - currentStream.write(0 + " j\n"); - } else if (str.equals("round")) { - currentStream.write(1 + " j\n"); - } else if (str.equals("bevel")) { - currentStream.write(2 + " j\n"); - } - } - } - } else { - } - sp = style.getPresentationAttribute("stroke-miterlimit"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - float width; - width = ((CSSPrimitiveValue) sp).getFloatValue( - CSSPrimitiveValue.CSS_PT); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.write(pdfNumber.doubleOut(width) + " M\n"); - } - } else { - } - sp = style.getPresentationAttribute("stroke-width"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - float width; - width = ((CSSPrimitiveValue) sp).getFloatValue( - CSSPrimitiveValue.CSS_PT); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.write(pdfNumber.doubleOut(width) + " w\n"); - } - } - sp = style.getPresentationAttribute("stroke-dasharray"); - if (sp != null) { - if (sp.getValueType() == CSSValue.CSS_VALUE_LIST) { - currentStream.write("[ "); - CSSValueList list = (CSSValueList) sp; - for (int count = 0; count < list.getLength(); count++) { - CSSValue val = list.item(count); - if (val.getValueType() == - CSSValue.CSS_PRIMITIVE_VALUE) { - currentStream.write( - ((CSSPrimitiveValue) val).getFloatValue( - CSSPrimitiveValue.CSS_NUMBER) + " "); - } - } - currentStream.write("] "); - sp = style.getPresentationAttribute("stroke-dashoffset"); - if (sp != null && sp.getValueType() == - CSSValue.CSS_PRIMITIVE_VALUE) { - currentStream.write( - ((CSSPrimitiveValue) sp).getFloatValue( - CSSPrimitiveValue.CSS_NUMBER) + " d\n"); - } else { - currentStream.write("0 d\n"); - } - } - } - sp = style.getPresentationAttribute("clip-path"); - if (sp != null) { - String clipurl; - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_URI) { - clipurl = ((CSSPrimitiveValue) sp).getCssText(); - if (clipurl.startsWith("url(")) { - int b1 = clipurl.indexOf("("); - int b2 = clipurl.indexOf(")"); - clipurl = clipurl.substring(b1 + 1, b2); - } - // get def of mask and set mask - SVGElement graph = null; - graph = locateDef(clipurl, area); - if (graph != null) { - MessageHandler.logln("clip path: " + graph); - // render the clip path elements and make it the clip - // renderElement(svgarea, graph, posx, posy); - } - } - } - } - sp = style.getPresentationAttribute("mask"); - if (sp != null) { - String maskurl; - if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_URI) { - maskurl = ((CSSPrimitiveValue) sp).getCssText(); - // System.out.println("mask: " + maskurl); - // get def of mask and set mask - if (maskurl.startsWith("url(")) { - int b1 = maskurl.indexOf("("); - int b2 = maskurl.indexOf(")"); - maskurl = maskurl.substring(b1 + 1, b2); - } - SVGElement graph = null; - graph = locateDef(maskurl, area); - if (graph != null) { - MessageHandler.logln("mask: " + graph); - // SVGElement parent = graph.getGraphicParent(); - // graph.setParent(area); - // renderElement(svgarea, graph, posx, posy); - // graph.setParent(parent); - } - } - } - } - return di; - } - - protected void applyTransform(SVGAnimatedTransformList trans) { - PDFNumber pdfNumber = new PDFNumber(); - SVGTransformList list = trans.getBaseVal(); - for (int count = 0; count < list.getNumberOfItems(); count++) { - SVGMatrix matrix = - ((SVGTransform) list.getItem(count)).getMatrix(); - currentStream.write(pdfNumber.doubleOut(matrix.getA()) + - " " + pdfNumber.doubleOut(matrix.getB()) + " " + - pdfNumber.doubleOut(matrix.getC()) + " " + - pdfNumber.doubleOut(matrix.getD()) + " " + - pdfNumber.doubleOut(matrix.getE()) + " " + - pdfNumber.doubleOut(matrix.getF()) + " cm\n"); - } - } - - /** - * Main rendering selection. - * This applies any transform and style and then calls the appropriate - * rendering method depending on the type of element. - */ - public void renderElement(SVGElement area, int posx, int posy) { - int x = posx; - int y = posy; - // CSSStyleDeclaration style = null; - // if(area instanceof SVGStylable) - // style = ((SVGStylable)area).getStyle(); - DrawingInstruction di = null; - - currentStream.write("q\n"); - if (area instanceof SVGTransformable) { - SVGTransformable tf = (SVGTransformable) area; - SVGAnimatedTransformList trans = tf.getTransform(); - if (trans != null) { - applyTransform(trans); - } - } - - if (area instanceof SVGStylable) { - di = applyStyle(area, (SVGStylable) area); - } - - if (area instanceof SVGRectElement) { - SVGRectElement rg = (SVGRectElement) area; - float rectx = rg.getX().getBaseVal().getValue(); - float recty = rg.getY().getBaseVal().getValue(); - float rx = rg.getRx().getBaseVal().getValue(); - float ry = rg.getRy().getBaseVal().getValue(); - float rw = rg.getWidth().getBaseVal().getValue(); - float rh = rg.getHeight().getBaseVal().getValue(); - addRect(rectx, recty, rw, rh, rx, ry, di); - } else if (area instanceof SVGLineElement) { - SVGLineElement lg = (SVGLineElement) area; - float x1 = lg.getX1().getBaseVal().getValue(); - float y1 = lg.getY1().getBaseVal().getValue(); - float x2 = lg.getX2().getBaseVal().getValue(); - float y2 = lg.getY2().getBaseVal().getValue(); - addLine(x1, y1, x2, y2, di); - } else if (area instanceof SVGTextElementImpl) { - // currentStream.add("q\n"); - // currentStream.add(1 + " " + 0 + " " + 0 + " " + 1 + " " + 0 + " " + 0 + " cm\n"); - currentStream.write("BT\n"); - renderText((SVGTextElementImpl) area, 0, 0, di); - currentStream.write("ET\n"); - // currentStream.add("Q\n"); - } else if (area instanceof SVGCircleElement) { - SVGCircleElement cg = (SVGCircleElement) area; - float cx = cg.getCx().getBaseVal().getValue(); - float cy = cg.getCy().getBaseVal().getValue(); - float r = cg.getR().getBaseVal().getValue(); - addCircle(cx, cy, r, di); - } else if (area instanceof SVGEllipseElement) { - SVGEllipseElement cg = (SVGEllipseElement) area; - float cx = cg.getCx().getBaseVal().getValue(); - float cy = cg.getCy().getBaseVal().getValue(); - float rx = cg.getRx().getBaseVal().getValue(); - float ry = cg.getRy().getBaseVal().getValue(); - addEllipse(cx, cy, rx, ry, di); - } else if (area instanceof SVGPathElementImpl) { - addPath(((SVGPathElementImpl) area).pathElements, posx, - posy, di); - } else if (area instanceof SVGPolylineElementImpl) { - addPolyline(((SVGPolylineElementImpl) area).points, di, false); - } else if (area instanceof SVGPolygonElementImpl) { - addPolyline(((SVGPolygonElementImpl) area).points, di, true); - } else if (area instanceof SVGGElementImpl) { - renderGArea((SVGGElementImpl) area, x, y); - } else if (area instanceof SVGUseElementImpl) { - SVGUseElementImpl ug = (SVGUseElementImpl) area; - String ref = ug.link; - // ref = ref.substring(1, ref.length()); - SVGElement graph = null; - graph = locateDef(ref, ug); - if (graph != null) { - // probably not the best way to do this, should be able - // to render without the style being set. - // SVGElement parent = graph.getGraphicParent(); - // graph.setParent(area); - // need to clip (if necessary) to the use area - // the style of the linked element is as if it was - // a direct descendant of the use element. - - // scale to the viewBox - - if (graph instanceof SVGSymbolElement) { - currentStream.write("q\n"); - SVGSymbolElement symbol = (SVGSymbolElement) graph; - SVGRect view = symbol.getViewBox().getBaseVal(); - float usex = ug.getX().getBaseVal().getValue(); - float usey = ug.getY().getBaseVal().getValue(); - float usewidth = ug.getWidth().getBaseVal().getValue(); - float useheight = - ug.getHeight().getBaseVal().getValue(); - float scaleX; - float scaleY; - scaleX = usewidth / view.getWidth(); - scaleY = useheight / view.getHeight(); - currentStream.write(usex + " " + usey + " m\n"); - currentStream.write((usex + usewidth) + " " + - usey + " l\n"); - currentStream.write((usex + usewidth) + " " + - (usey + useheight) + " l\n"); - currentStream.write(usex + " " + - (usey + useheight) + " l\n"); - currentStream.write("h\n"); - currentStream.write("W\n"); - currentStream.write("n\n"); - currentStream.write(scaleX + " 0 0 " + scaleY + - " " + usex + " " + usey + " cm\n"); - renderSymbol(symbol, posx, posy); - currentStream.write("Q\n"); - } else { - renderElement(graph, posx, posy); - } - // graph.setParent(parent); - } - else { - MessageHandler.logln("Use Element: " + ref + " not found"); - } - } else if (area instanceof SVGImageElementImpl) { - SVGImageElementImpl ig = (SVGImageElementImpl) area; - renderImage(ig.link, ig.x, ig.y, ig.width, ig.height); - } else if (area instanceof SVGSVGElement) { - currentStream.write("q\n"); - SVGSVGElement svgel = (SVGSVGElement) area; - float svgx = 0; - if (svgel.getX() != null) - svgx = svgel.getX().getBaseVal().getValue(); - float svgy = 0; - if (svgel.getY() != null) - svgy = svgel.getY().getBaseVal().getValue(); - currentStream.write(1 + " 0 0 " + 1 + " " + svgx + " " + - svgy + " cm\n"); - renderSVG(svgel, (int)(x + 1000 * svgx), - (int)(y + 1000 * svgy)); - currentStream.write("Q\n"); - // } else if (area instanceof SVGSymbolElement) { - // 'symbol' element is not rendered (except by 'use') - } else if (area instanceof SVGAElement) { - SVGAElement ael = (SVGAElement) area; - org.w3c.dom.NodeList nl = ael.getChildNodes(); - for (int count = 0; count < nl.getLength(); count++) { - org.w3c.dom.Node n = nl.item(count); - if (n instanceof SVGElement) { - if (n instanceof GraphicElement) { - SVGRect rect = ((GraphicElement) n).getBBox(); - if (rect != null) { - /* currentAnnotList = this.pdfDoc.makeAnnotList(); - currentPage.setAnnotList(currentAnnotList); - String dest = linkSet.getDest(); - int linkType = linkSet.getLinkType(); - currentAnnotList.addLink( - this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType)); - currentAnnotList = null; - */ } - } - renderElement((SVGElement) n, posx, posy); - } - } - } else if (area instanceof SVGSwitchElement) { - handleSwitchElement(posx, posy, (SVGSwitchElement) area); - } - // should be done with some cleanup code, so only - // required values are reset. - currentStream.write("Q\n"); - } - - /** - * Todo: underline, linethrough, textpath - */ - public void renderText(SVGTextElementImpl tg, float x, float y, - DrawingInstruction di) { - SVGTextRenderer str = new SVGTextRenderer(fontState, tg, x, y); - if (di.fill) { - if (di.stroke) { - currentStream.write("2 Tr\n"); - } else { - currentStream.write("0 Tr\n"); - } - } else if (di.stroke) { - currentStream.write("1 Tr\n"); - } - str.renderText(tg); - } - - /** - * Adds an svg string to the output. - * This handles the escaping of special pdf chars and deals with - * whitespace. - */ - protected float addSVGStr(FontState fs, float currentX, String str, - boolean spacing) { - boolean inbetween = false; - boolean addedspace = false; - StringBuffer pdf = new StringBuffer(); - for (int i = 0; i < str.length(); i++) { - char ch = str.charAt(i); - if (ch > 127) { - pdf = pdf.append("\\"); - pdf = pdf.append(Integer.toOctalString((int) ch)); - currentX += fs.width(ch) / 1000f; - inbetween = true; - addedspace = false; - } else { - switch (ch) { - case '(' : - pdf = pdf.append("\\("); - currentX += fs.width(ch) / 1000f; - inbetween = true; - addedspace = false; - break; - case ')' : - pdf = pdf.append("\\)"); - currentX += fs.width(ch) / 1000f; - inbetween = true; - addedspace = false; - break; - case '\\' : - pdf = pdf.append("\\\\"); - currentX += fs.width(ch) / 1000f; - inbetween = true; - addedspace = false; - break; - case '\t': - case ' ': - if (spacing) { - pdf = pdf.append(' '); - currentX += fs.width(' ') / 1000f; - } else { - if (inbetween && !addedspace) { - addedspace = true; - pdf = pdf.append(' '); - currentX += fs.width(' ') / 1000f; - } - } - break; - case '\n': - case '\r': - if (spacing) { - pdf = pdf.append(' '); - currentX += fs.width(' ') / 1000f; - } - break; - default: - addedspace = false; - pdf = pdf.append(ch); - currentX += fs.width(ch) / 1000f; - inbetween = true; - break; - } - } - } - currentStream.write(pdf.toString()); - return currentX; - } - - /** - * Locates a defined element in an svg document. - * Either gets the element defined by its "id" in the current - * SVGDocument, or if the uri reference is to an external - * document it loads the document and returns the element. - */ - protected SVGElement locateDef(String ref, SVGElement currentElement) { - int pos; - ref = ref.trim(); - pos = ref.indexOf("#"); - if (pos == 0) { - // local doc - Document doc = currentElement.getOwnerDocument(); - Element ele = - doc.getElementById(ref.substring(1, ref.length())); - if (ele instanceof SVGElement) { - return (SVGElement) ele; - } - } else if (pos != -1) { - String href = ref.substring(0, pos); - if (href.indexOf(":") == -1) { - href = "file:" + href; - } - try { - // this is really only to get a cached svg image - FopImage img = FopImageFactory.Make(href); - if (img instanceof SVGImage) { - SVGDocument doc = ((SVGImage) img).getSVGDocument(); - Element ele = doc.getElementById( - ref.substring(pos + 1, ref.length())); - if (ele instanceof SVGElement) { - return (SVGElement) ele; - } - } - } catch (Exception e) { - MessageHandler.errorln(e.toString()); - } - } - return null; - } - - /** - * This class is used to handle the rendering of svg text. - * This is so that it can deal with the recursive rendering - * of text markup, while keeping track of the state and position. - */ - class SVGTextRenderer { - FontState fs; - String transstr; - float currentX; - float currentY; - float baseX; - float baseY; - SVGMatrix matrix; - float x; - float y; - - SVGTextRenderer(FontState fontState, SVGTextElementImpl tg, - float x, float y) { - fs = fontState; - - PDFNumber pdfNumber = new PDFNumber(); - SVGTransformList trans = tg.getTransform().getBaseVal(); - matrix = trans.consolidate().getMatrix(); - transstr = (pdfNumber.doubleOut(matrix.getA()) + " " + - pdfNumber.doubleOut(matrix.getB()) + " " + - pdfNumber.doubleOut(matrix.getC()) + " " + - pdfNumber.doubleOut(-matrix.getD()) + " "); - this.x = x; - this.y = y; - } - - void renderText(SVGTextElementImpl te) { - DrawingInstruction di = applyStyle(te, te); - if (di.fill) { - if (di.stroke) { - currentStream.write("2 Tr\n"); - } else { - currentStream.write("0 Tr\n"); - } - } else if (di.stroke) { - currentStream.write("1 Tr\n"); - } - updateFont(te, fs); - - float tx = te.x; - float ty = te.y; - currentX = x + tx; - currentY = y + ty; - baseX = currentX; - baseY = currentY; - NodeList nodel = te.getChildNodes(); - // Vector list = te.textList; - for (int count = 0; count < nodel.getLength(); count++) { - Object o = nodel.item(count); - applyStyle(te, te); - if (o instanceof CharacterData) { - String str = ((CharacterData) o).getData(); - currentStream.write(transstr + - (currentX + matrix.getE()) + " " + - (baseY + matrix.getF()) + " Tm " + "("); - boolean spacing = "preserve".equals(te.getXMLspace()); - currentX = addSVGStr(fs, currentX, str, spacing); - currentStream.write(") Tj\n"); - } else if (o instanceof SVGTextPathElementImpl) { - SVGTextPathElementImpl tpg = (SVGTextPathElementImpl) o; - String ref = tpg.str; - SVGElement graph = null; - graph = locateDef(ref, tpg); - if (graph instanceof SVGPathElementImpl) { - // probably not the best way to do this, should be able - // to render without the style being set. - // GraphicImpl parent = graph.getGraphicParent(); - // graph.setParent(tpg); - // set text path?? - // how should this work - // graph.setParent(parent); - } - } else if (o instanceof SVGTRefElementImpl) { - SVGTRefElementImpl trg = (SVGTRefElementImpl) o; - String ref = trg.ref; - SVGElement element = locateDef(ref, trg); - if (element instanceof SVGTextElementImpl) { - // GraphicImpl parent = graph.getGraphicParent(); - // graph.setParent(trg); - SVGTextElementImpl tele = - (SVGTextElementImpl) element; - // the style should be from tele, but it needs to be placed as a child - // of trg to work - di = applyStyle(trg, trg); - if (di.fill) { - if (di.stroke) { - currentStream.write("2 Tr\n"); - } else { - currentStream.write("0 Tr\n"); - } - } else if (di.stroke) { - currentStream.write("1 Tr\n"); - } - boolean changed = false; - FontState oldfs = fs; - changed = updateFont(te, fs); - NodeList nl = tele.getChildNodes(); - boolean spacing = - "preserve".equals(trg.getXMLspace()); - renderTextNodes(spacing, nl, - trg.getX().getBaseVal(), - trg.getY().getBaseVal(), - trg.getDx().getBaseVal(), - trg.getDy().getBaseVal()); - - if (changed) { - fs = oldfs; - currentStream.write("/" + - fs.getFontName() + " " + - fs.getFontSize() / 1000f + " Tf\n"); - } - // graph.setParent(parent); - } - } else if (o instanceof SVGTSpanElementImpl) { - SVGTSpanElementImpl tsg = (SVGTSpanElementImpl) o; - applyStyle(tsg, tsg); - boolean changed = false; - FontState oldfs = fs; - changed = updateFont(tsg, fs); - boolean spacing = "preserve".equals(tsg.getXMLspace()); - renderTextNodes(spacing, tsg.getChildNodes(), - tsg.getX().getBaseVal(), - tsg.getY().getBaseVal(), - tsg.getDx().getBaseVal(), - tsg.getDy().getBaseVal()); - - // currentX += fs.width(' ') / 1000f; - if (changed) { - fs = oldfs; - currentStream.write("/" + fs.getFontName() + - " " + fs.getFontSize() / 1000f + " Tf\n"); - } - } else { - MessageHandler.errorln("Error: unknown text element " + o); - } - } - } - - void renderTextNodes(boolean spacing, NodeList nl, - SVGLengthList xlist, SVGLengthList ylist, - SVGLengthList dxlist, SVGLengthList dylist) { - boolean inbetween = false; - boolean addedspace = false; - int charPos = 0; - float xpos = currentX; - float ypos = currentY; - - for (int count = 0; count < nl.getLength(); count++) { - Node n = nl.item(count); - if (n instanceof CharacterData) { - StringBuffer pdf = new StringBuffer(); - String str = ((CharacterData) n).getData(); - for (int i = 0; i < str.length(); i++) { - char ch = str.charAt(i); - xpos = currentX; - ypos = currentY; - if (ylist.getNumberOfItems() > charPos) { - ypos = baseY + (ylist.getItem(charPos)). - getValue(); - } - if (dylist.getNumberOfItems() > charPos) { - ypos = ypos + (dylist.getItem(charPos)). - getValue(); - } - if (xlist.getNumberOfItems() > charPos) { - xpos = baseX + (xlist.getItem(charPos)). - getValue(); - } - if (dxlist.getNumberOfItems() > charPos) { - xpos = xpos + (dxlist.getItem(charPos)). - getValue(); - } - if (ch > 127) { - pdf = pdf.append(transstr + - (xpos + matrix.getE()) + " " + - (ypos + matrix.getF()) + " Tm " + - "(" + "\\" + - Integer.toOctalString((int) ch) + - ") Tj\n"); - currentX = xpos + fs.width(ch) / 1000f; - currentY = ypos; - charPos++; - inbetween = true; - addedspace = false; - } else { - switch (ch) { - case '(' : - pdf = pdf.append(transstr + - (xpos + matrix.getE()) + - " " + (ypos + - matrix.getF()) + " Tm " + - "(" + "\\(" + ") Tj\n"); - currentX = xpos + fs.width(ch) / 1000f; - currentY = ypos; - charPos++; - inbetween = true; - addedspace = false; - break; - case ')' : - pdf = pdf.append(transstr + - (xpos + matrix.getE()) + - " " + (ypos + - matrix.getF()) + " Tm " + - "(" + "\\)" + ") Tj\n"); - currentX = xpos + fs.width(ch) / 1000f; - currentY = ypos; - charPos++; - inbetween = true; - addedspace = false; - break; - case '\\' : - pdf = pdf.append(transstr + - (xpos + matrix.getE()) + - " " + (ypos + - matrix.getF()) + " Tm " + - "(" + "\\\\" + ") Tj\n"); - currentX = xpos + fs.width(ch) / 1000f; - currentY = ypos; - charPos++; - inbetween = true; - addedspace = false; - break; - case '\t': - case ' ': - if (spacing) { - currentX = xpos + fs.width(' ') / - 1000f; - currentY = ypos; - charPos++; - } else { - if (inbetween && !addedspace) { - addedspace = true; - currentX = xpos + fs.width(' ') - / 1000f; - currentY = ypos; - charPos++; - } - } - break; - case '\n': - case '\r': - if (spacing) { - currentX = xpos + fs.width(' ') / - 1000f; - currentY = ypos; - charPos++; - } - break; - default: - addedspace = false; - pdf = pdf.append(transstr + - (xpos + matrix.getE()) + - " " + (ypos + - matrix.getF()) + " Tm " + - "(" + ch + ") Tj\n"); - currentX = xpos + fs.width(ch) / 1000f; - currentY = ypos; - charPos++; - inbetween = true; - break; - } - } - currentStream.write(pdf.toString()); - } - } - } - } - - protected boolean updateFont(SVGStylable style, FontState fs) { - boolean changed = false; - String fontFamily = fs.getFontFamily(); - CSSValue sp = style.getPresentationAttribute("font-family"); - if (sp != null && - sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - fontFamily = sp.getCssText(); - } - } - if (!fontFamily.equals(fs.getFontFamily())) { - changed = true; - } - String fontStyle = fs.getFontStyle(); - sp = style.getPresentationAttribute("font-style"); - if (sp != null && - sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - fontStyle = sp.getCssText(); - } - } - if (!fontStyle.equals(fs.getFontStyle())) { - changed = true; - } - String fontWeight = fs.getFontWeight(); - sp = style.getPresentationAttribute("font-weight"); - if (sp != null && - sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - if (((CSSPrimitiveValue) sp).getPrimitiveType() == - CSSPrimitiveValue.CSS_STRING) { - fontWeight = sp.getCssText(); - } - } - if (!fontWeight.equals(fs.getFontWeight())) { - changed = true; - } - float newSize = fs.getFontSize() / 1000f; - sp = style.getPresentationAttribute("font-size"); - if (sp != null && - sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { - // if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_NUMBER) { - newSize = ((CSSPrimitiveValue) sp).getFloatValue( - CSSPrimitiveValue.CSS_PT); - // } - } - if (fs.getFontSize() / 1000f != newSize) { - changed = true; - } - if (changed) { - try { - fs = new FontState(fs.getFontInfo(), fontFamily, - fontStyle, fontWeight, (int)(newSize * 1000)); - } catch (Exception fope) { - } - this.fs = fs; - - currentStream.write("/" + fs.getFontName() + " " + - newSize + " Tf\n"); - } else { - if (!currentFontName.equals(fs.getFontName()) || - currentFontSize != fs.getFontSize()) { - // currentFontName = fs.getFontName(); - // currentFontSize = fs.getFontSize(); - currentStream.write("/" + fs.getFontName() + " " + - (fs.getFontSize() / 1000) + " Tf\n"); - } - } - return changed; - } - } + double ry = vals[1]; + double theta = vals[2]; + boolean largearcflag = (vals[3] == 1.0); + boolean sweepflag = (vals[4] == 1.0); + + double angle = Math.atan(vals[6] / vals[5]); + double relangle = Math.atan(ry / rx); + // System.out.println((theta * Math.PI / 180f) + ":" + relangle + ":" + largearcflag + ":" + sweepflag); + double absangle = (theta * Math.PI / 180f);//angle + relangle; + // change sign depending on flags + double contrx1; + double contry1; + double contrx2; + double contry2; + if (largearcflag) { + // in a large arc we need to do at least 2 and a bit + // segments or curves. + if (sweepflag) { + contrx1 = lastx + rx * Math.cos(absangle); + contry1 = lasty + rx * Math.sin(absangle); + contrx2 = lastx + vals[5] + + ry * Math.cos(absangle); + contry2 = lasty + vals[6] - + ry * Math.sin(absangle); + } else { + contrx1 = lastx + rx * Math.sin(absangle); + contry1 = lasty + rx * Math.cos(absangle); + contrx2 = lastx + vals[5] + + ry * Math.cos(absangle); + contry2 = lasty + vals[6] + + ry * Math.sin(absangle); + } + } else { + // only need at most two segments + if (sweepflag) { + contrx1 = lastx + rx * Math.cos(absangle); + contry1 = lasty - rx * Math.sin(absangle); + contrx2 = contrx1; + contry2 = contry1; + } else { + contrx1 = lastx - ry * Math.cos(absangle); + contry1 = lasty + ry * Math.sin(absangle); + contrx2 = contrx1; + contry2 = contry1; + } + } + //System.out.println(contrx1 + ":" + contry1 + ":" + contrx2 + ":" + contry2); + + double cx = lastx; + double cy = lasty; + currentStream.write(pdfNumber.doubleOut(contrx1) + " " + pdfNumber.doubleOut(contry1) + + " " + pdfNumber.doubleOut(contrx2) + " " + pdfNumber.doubleOut(contry2) + " " + + pdfNumber.doubleOut(vals[5] + lastx) + " " + + pdfNumber.doubleOut(vals[6] + lasty) + " c\n"); + + lastcx = 0; //?? + lastcy = 0; //?? + lastx += vals[5]; + lasty += vals[6];*/ + } + break; + case SVGPathSeg.PATHSEG_CLOSEPATH: + currentStream.write("h\n"); + pathmoveto = null; + lastx = lastmovex; + lasty = lastmovey; + break; + } + } + doDrawing(di); + } + + /** + * Calculate the last control point for a bezier curve. + * This is used to find the last control point for a curve where + * only the first control point is specified. + * The control point is a reflection of the first control point + * which results in an even smooth curve. The curve is symmetrical. + */ + protected float[] calculateLastControl(float x1, float y1, float x2, float y2, float relx, float rely) + { + float vals[] = new float[2]; + relx = -relx; + rely = -rely; + float dist = (float)Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); + float costheta = (float)(x2 - x1) / dist; + float sinetheta = (float)(y2 - y1) / dist; + float temp = relx; + relx = relx * costheta + rely * sinetheta; + rely = -temp * sinetheta + rely * costheta; + relx = -relx; + temp = relx; + relx = relx * costheta - rely * sinetheta; + rely = temp * sinetheta + rely * costheta; + vals[0] = x2 - relx; + vals[1] = y2 - rely; + return vals; + } + + /** + * Adds an SVG polyline or polygon. + * A polygon is merely a closed polyline. + * This is made up from a set of points that straight lines are drawn between. + */ + protected void addPolyline(Vector points, DrawingInstruction di, + boolean close) { + PDFNumber pdfNumber = new PDFNumber(); + PathPoint pc; + float lastx = 0; + float lasty = 0; + Enumeration e = points.elements(); + if (e.hasMoreElements()) { + pc = (PathPoint) e.nextElement(); + lastx = pc.x; + lasty = pc.y; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " m\n"); + } + while (e.hasMoreElements()) { + pc = (PathPoint) e.nextElement(); + lastx = pc.x; + lasty = pc.y; + currentStream.write(pdfNumber.doubleOut(lastx) + " " + pdfNumber.doubleOut(lasty) + " l\n"); + } + if (close) + currentStream.write("h\n"); + doDrawing(di); + } + + /** + * Writes the drawing instruction out to the current stream + * depending on what type of drawing is required. + */ + protected void doDrawing(DrawingInstruction di) { + if (di == null) { + currentStream.write("S\n"); + } else { + if (di.fill) { + if (di.stroke) { + if (!di.nonzero) + currentStream.write("B*\n"); + else + currentStream.write("B\n"); + } else { + if (!di.nonzero) + currentStream.write("f*\n"); + else + currentStream.write("f\n"); + } + } else { + // if(di.stroke) + currentStream.write("S\n"); + } + } + } + + /** + * Renders an svg image to the current stream. + * This uses the FopImageFactory to load the image and then renders it. + */ + public void renderImage(String href, float x, float y, float width, + float height) { + try { + if (href.indexOf(":") == -1) { + href = "file:" + href; + } + FopImage img = FopImageFactory.Make(href); + PDFNumber pdfNumber = new PDFNumber(); + if (img instanceof SVGImage) { + SVGSVGElement svg = + ((SVGImage) img).getSVGDocument().getRootElement(); + currentStream.write("q\n" + pdfNumber.doubleOut(width / + svg.getWidth().getBaseVal().getValue()) + " 0 0 " + + pdfNumber.doubleOut(height / + svg.getHeight().getBaseVal().getValue()) + " 0 0 cm\n"); + renderSVG(svg, (int) x * 1000, (int) y * 1000); + currentStream.write("Q\n"); + // renderSVG(svg); + } else if (img != null) { + int xObjectNum = this.pdfDoc.addImage(img); + currentStream.write("q\n1 0 0 -1 0 " + + pdfNumber.doubleOut(2 * y + height) + " cm\n" + pdfNumber.doubleOut(width) + " 0 0 " + + pdfNumber.doubleOut(height) + " " + pdfNumber.doubleOut(x) + " " + pdfNumber.doubleOut(y) + " cm\n" + "/Im" + + xObjectNum + " Do\nQ\n"); + // img.close(); + } + } catch (Exception e) { + MessageHandler.errorln("could not add image to SVG: " + href); + } + } + + /** + * A symbol has a viewbox and preserve aspect ratio. + */ + protected void renderSymbol(SVGSymbolElement symbol, int x, int y) { + NodeList nl = symbol.getChildNodes(); + for (int count = 0; count < nl.getLength(); count++) { + Node n = nl.item(count); + if (n instanceof SVGElement) { + renderElement((SVGElement) n, x, y); + } + } + } + + /** + * Handles the construction of an SVG gradient. + * This gets the gradient element and creates the pdf info + * in the pdf document. + * The type of gradient is determined by what class the gradient element is. + */ + protected void handleGradient(String sp, DrawingInstruction di, + boolean fill, SVGElement area) { + // should be a url to a gradient + String url = (String) sp; + if (url.startsWith("url(")) { + String address; + int b1 = url.indexOf("("); + int b2 = url.indexOf(")"); + address = url.substring(b1 + 1, b2); + SVGElement gi = null; + gi = locateDef(address, area); + if (gi instanceof SVGLinearGradientElement) { + SVGLinearGradientElement linear = + (SVGLinearGradientElement) gi; + handleLinearGradient(linear, di, fill, area); + } else if (gi instanceof SVGRadialGradientElement) { + SVGRadialGradientElement radial = + (SVGRadialGradientElement) gi; + handleRadialGradient(radial, di, fill, area); + } else if (gi instanceof SVGPatternElement) { + SVGPatternElement pattern = (SVGPatternElement) gi; + handlePattern(pattern, di, fill, area); + } else { + MessageHandler.errorln("WARNING Invalid fill reference :" + + gi + ":" + address); + } + } + } + + protected void handlePattern(SVGPatternElement pattern, + DrawingInstruction di, boolean fill, SVGElement area) { + SVGAnimatedLength x, y, width, height; + short pattUnits = SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN; + NodeList stops = null; + x = pattern.getX(); + y = pattern.getY(); + width = pattern.getWidth(); + height = pattern.getHeight(); + NodeList nl = pattern.getChildNodes(); + SVGPatternElement ref = (SVGPatternElement) locateDef( + pattern.getHref().getBaseVal(), pattern); + while (ref != null) { + if (x == null) { + x = ref.getX(); + pattUnits = ref.getPatternUnits().getBaseVal(); + } + if (y == null) { + y = ref.getY(); + } + if (width == null) { + width = ref.getWidth(); + } + if (height == null) { + height = ref.getHeight(); + } + if (nl.getLength() == 0) { + nl = ref.getChildNodes(); + } + ref = (SVGPatternElement) locateDef( + ref.getHref().getBaseVal(), ref); + } + if (x == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); + x = new SVGAnimatedLengthImpl(length); + } + if (y == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); + y = new SVGAnimatedLengthImpl(length); + } + if (width == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); + width = new SVGAnimatedLengthImpl(length); + } + if (height == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); + height = new SVGAnimatedLengthImpl(length); + } + + StringWriter realStream = currentStream; + currentStream = new StringWriter(); + + currentStream.write("q\n"); + // this makes the pattern the right way up, since it is outside the original + // transform around the whole svg document + currentStream.write("1 0 0 -1 0 " + + height.getBaseVal().getValue() + " cm\n"); + for (int count = 0; count < nl.getLength(); count++) { + Node n = nl.item(count); + if (n instanceof SVGElement) { + renderElement((SVGElement) n, 0, 0); + } + } + currentStream.write("Q\n"); + + double xval = x.getBaseVal().getValue() + currentXPosition / 1000f; + double yval = -y.getBaseVal().getValue() + currentYPosition / 1000f; + if (area instanceof GraphicElement) { + SVGRect bbox = ((GraphicElement) area).getBBox(); + if (bbox != null) { + // xval += bbox.getX(); + // yval -= bbox.getY(); + } + } + double widthval = width.getBaseVal().getValue(); + double heightval = height.getBaseVal().getValue(); + Vector bbox = new Vector(); + bbox.addElement(new Double(0)); + bbox.addElement(new Double(0)); + bbox.addElement(new Double(widthval)); + bbox.addElement(new Double(heightval)); + Vector translate = new Vector(); + // combine with pattern transform + translate.addElement(new Double(1)); + translate.addElement(new Double(0)); + translate.addElement(new Double(0)); + translate.addElement(new Double(1)); + translate.addElement(new Double(xval)); + translate.addElement(new Double(yval)); + // need to handle PDFResources + PDFPattern myPat = + this.pdfDoc.makePattern(1, null, 1, 1, bbox, widthval, + heightval, translate, null, currentStream.getBuffer()); + + currentStream = realStream; + currentStream.write(myPat.getColorSpaceOut(fill)); + if (fill) + di.fill = true; + else + di.stroke = true; + } + + protected void handleLinearGradient( + SVGLinearGradientElement linear, DrawingInstruction di, + boolean fill, SVGElement area) { + // first get all the gradient values + // if values not present follow the href + // the gradient units will be where the vals are specified + // the spread method will be where there are stop elements + SVGAnimatedLength ax1, ax2, ay1, ay2; + short spread = SVGGradientElement.SVG_SPREADMETHOD_UNKNOWN; + short gradUnits = SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN; + NodeList stops = null; + ax1 = linear.getX1(); + ax2 = linear.getX2(); + ay1 = linear.getY1(); + ay2 = linear.getY2(); + stops = linear.getChildNodes(); + SVGLinearGradientElement ref = (SVGLinearGradientElement) locateDef( + linear.getHref().getBaseVal(), linear); + while (ref != null) { + if (ax1 == null) { + ax1 = ref.getX1(); + gradUnits = ref.getGradientUnits().getBaseVal(); + } + if (ax2 == null) { + ax2 = ref.getX2(); + } + if (ay1 == null) { + ay1 = ref.getY1(); + } + if (ay2 == null) { + ay2 = ref.getY2(); + } + if (stops.getLength() == 0) { + stops = ref.getChildNodes(); + } + ref = (SVGLinearGradientElement) locateDef( + ref.getHref().getBaseVal(), ref); + } + if (ax1 == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); + ax1 = new SVGAnimatedLengthImpl(length); + } + if (ax2 == null) { + // if x2 is not specified then it should be 100% + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); + ax2 = new SVGAnimatedLengthImpl(length); + } + if (ay1 == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); + ay1 = new SVGAnimatedLengthImpl(length); + } + if (ay2 == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0); + ay2 = new SVGAnimatedLengthImpl(length); + } + SVGAnimatedTransformList an = linear.getGradientTransform(); + SVGMatrix transform = null; + if(an != null) + transform = an.getBaseVal().consolidate().getMatrix(); + Vector theCoords = null; + if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_UNKNOWN) + gradUnits = linear.getGradientUnits().getBaseVal(); + // spread: pad (normal), reflect, repeat + spread = linear.getSpreadMethod().getBaseVal(); + if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE) { + if (area instanceof SVGTransformable) { + SVGTransformable tf = (SVGTransformable) area; + double x1, y1, x2, y2; + x1 = ax1.getBaseVal().getValue(); + y1 = -ay1.getBaseVal().getValue(); + x2 = ax2.getBaseVal().getValue(); + y2 = -ay2.getBaseVal().getValue(); + SVGMatrix matrix = tf.getScreenCTM(); + if(transform != null) + matrix = matrix.multiply(transform); + double oldx = x1; + x1 = matrix.getA() * x1 + matrix.getC() * y1 + + matrix.getE(); + y1 = matrix.getB() * oldx + matrix.getD() * y1 - + matrix.getF(); + oldx = x2; + x2 = matrix.getA() * x2 + matrix.getC() * y2 + + matrix.getE(); + y2 = matrix.getB() * oldx + matrix.getD() * y2 - + matrix.getF(); + theCoords = new Vector(); + if (spread == SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { + } else if (spread == + SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + x1)); + theCoords.addElement( + new Double(currentYPosition / 1000f + y1)); + theCoords.addElement( + new Double(currentXPosition / 1000f + x2)); + theCoords.addElement( + new Double(currentYPosition / 1000f + y2)); + } + } + } else if (area instanceof GraphicElement) { + SVGRect rect = ((GraphicElement) area).getBBox(); + if (rect != null) { + theCoords = new Vector(); + SVGLength val; + val = ax1.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentXPosition / 1000f + + rect.getX() + + val.getValue() * rect.getWidth())); + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + + val.getValue())); + } + val = ay1.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentYPosition / 1000f - + rect.getY() - + val.getValue() * rect.getHeight())); + } else { + theCoords.addElement( + new Double(currentYPosition / 1000f - + val.getValue())); + } + val = ax2.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentXPosition / 1000f + + rect.getX() + + val.getValue() * rect.getWidth())); + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + + val.getValue())); + } + val = ay2.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentYPosition / 1000f - + rect.getY() - + val.getValue() * rect.getHeight())); + } else { + theCoords.addElement( + new Double(currentYPosition / 1000f - + val.getValue())); + } + } + } + if (theCoords == null) { + theCoords = new Vector(); + theCoords.addElement( new Double(currentXPosition / 1000f + + ax1.getBaseVal().getValue())); + theCoords.addElement( new Double(currentYPosition / 1000f - + ay1.getBaseVal().getValue())); + theCoords.addElement( new Double(currentXPosition / 1000f + + ax2.getBaseVal().getValue())); + theCoords.addElement( new Double(currentYPosition / 1000f - + ay2.getBaseVal().getValue())); + } + + Vector theExtend = new Vector(); + theExtend.addElement(new Boolean(true)); + theExtend.addElement(new Boolean(true)); + + Vector theDomain = new Vector(); + theDomain.addElement(new Double(0)); + theDomain.addElement(new Double(1)); + + Vector theEncode = new Vector(); + theEncode.addElement(new Double(0)); + theEncode.addElement(new Double(1)); + theEncode.addElement(new Double(0)); + theEncode.addElement(new Double(1)); + + Vector theBounds = new Vector(); + theBounds.addElement(new Double(0)); + theBounds.addElement(new Double(1)); + + Vector theFunctions = new Vector(); + + NodeList nl = stops; + Vector someColors = new Vector(); + float lastoffset = 0; + Vector lastVector = null; + SVGStopElementImpl stop; + if (nl.getLength() == 0) { + // the color should be "none" + if (fill) + di.fill = false; + else + di.stroke = false; + return; + } else if (nl.getLength() == 1) { + stop = (SVGStopElementImpl) nl.item(0); + CSSValue cv = stop.getPresentationAttribute("stop-color"); + if (cv == null) { + // maybe using color + cv = stop.getPresentationAttribute("color"); + } + if (cv == null) { + // problems + MessageHandler.errorln("no stop-color or color in stop element"); + return; + } + PDFColor color = new PDFColor(0, 0, 0); + if (cv != null && + cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) cv).getPrimitiveType() == + CSSPrimitiveValue.CSS_RGBCOLOR) { + RGBColor col = + ((CSSPrimitiveValue) cv).getRGBColorValue(); + CSSPrimitiveValue val; + val = col.getRed(); + float red = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getGreen(); + float green = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getBlue(); + float blue = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + color = new PDFColor(red, green, blue); + } + } + currentStream.write(color.getColorSpaceOut(fill)); + if (fill) + di.fill = true; + else + di.stroke = true; + return; + } + for (int count = 0; count < nl.getLength(); count++) { + stop = (SVGStopElementImpl) nl.item(count); + CSSValue cv = stop.getPresentationAttribute("stop-color"); + if (cv == null) { + // maybe using color + cv = stop.getPresentationAttribute("color"); + } + if (cv == null) { + // problems + MessageHandler.errorln("no stop-color or color in stop element"); + continue; + } + PDFColor color = new PDFColor(0, 0, 0); + if (cv != null && + cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) cv).getPrimitiveType() == + CSSPrimitiveValue.CSS_RGBCOLOR) { + RGBColor col = + ((CSSPrimitiveValue) cv).getRGBColorValue(); + CSSPrimitiveValue val; + val = col.getRed(); + float red = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getGreen(); + float green = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getBlue(); + float blue = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + color = new PDFColor(red, green, blue); + currentColour = color; + } + } + float offset = stop.getOffset().getBaseVal(); + Vector colVector = color.getVector(); + // create bounds from last to offset + if (lastVector != null) { + Vector theCzero = lastVector; + Vector theCone = colVector; + PDFFunction myfunc = + this.pdfDoc.makeFunction(2, theDomain, null, + theCzero, theCone, 1.0); + theFunctions.addElement(myfunc); + } + lastoffset = offset; + lastVector = colVector; + someColors.addElement(color); + } + ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); + /* PDFFunction myfunky = this.pdfDoc.makeFunction(3, + theDomain, null, + theFunctions, null, + theEncode); + PDFShading myShad = null; + myShad = this.pdfDoc.makeShading( + 2, aColorSpace, + null, null, false, + theCoords, null, myfunky,theExtend); + PDFPattern myPat = this.pdfDoc.makePattern(2, myShad, null, null, null);*/ + PDFPattern myPat = this.pdfDoc.createGradient(false, aColorSpace, + someColors, null, theCoords); + currentStream.write(myPat.getColorSpaceOut(fill)); + if (fill) + di.fill = true; + else + di.stroke = true; + } + + protected void handleRadialGradient( + SVGRadialGradientElement radial, DrawingInstruction di, + boolean fill, SVGElement area) { + // first get all the gradient values + // if values not present follow the href + // the gradient units will be where the vals are specified + SVGAnimatedLength acx, acy, ar, afx, afy; + short gradUnits = radial.getGradientUnits().getBaseVal(); + NodeList stops = null; + acx = radial.getCx(); + acy = radial.getCy(); + ar = radial.getR(); + afx = radial.getFx(); + afy = radial.getFy(); + stops = radial.getChildNodes(); + SVGRadialGradientElement ref = (SVGRadialGradientElement) locateDef( + radial.getHref().getBaseVal(), radial); + while (ref != null) { + if (acx == null) { + acx = ref.getCx(); + gradUnits = ref.getGradientUnits().getBaseVal(); + } + if (acy == null) { + acy = ref.getCy(); + } + if (ar == null) { + ar = ref.getR(); + } + if (afx == null) { + afx = ref.getFx(); + } + if (afy == null) { + afy = ref.getFy(); + } + if (stops.getLength() == 0) { + stops = ref.getChildNodes(); + } + ref = (SVGRadialGradientElement) locateDef( + ref.getHref().getBaseVal(), ref); + } + if (acx == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); + acx = new SVGAnimatedLengthImpl(length); + } + if (acy == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); + acy = new SVGAnimatedLengthImpl(length); + } + if (ar == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 1); + ar = new SVGAnimatedLengthImpl(length); + } + if (afx == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); + afx = new SVGAnimatedLengthImpl(length); + } + if (afy == null) { + SVGLength length = new SVGLengthImpl(); + length.newValueSpecifiedUnits( + SVGLength.SVG_LENGTHTYPE_PERCENTAGE, 0.5f); + afy = new SVGAnimatedLengthImpl(length); + } + ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); + org.w3c.dom.NodeList nl = stops; + SVGStopElementImpl stop; + if (nl.getLength() == 0) { + // the color should be "none" + if (fill) + di.fill = false; + else + di.stroke = false; + return; + } else if (nl.getLength() == 1) { + stop = (SVGStopElementImpl) nl.item(0); + CSSValue cv = stop.getPresentationAttribute("stop-color"); + if (cv == null) { + // maybe using color + cv = stop.getPresentationAttribute("color"); + } + if (cv == null) { + // problems + MessageHandler.errorln("no stop-color or color in stop element"); + return; + } + PDFColor color = new PDFColor(0, 0, 0); + if (cv != null && + cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) cv).getPrimitiveType() == + CSSPrimitiveValue.CSS_RGBCOLOR) { + RGBColor col = + ((CSSPrimitiveValue) cv).getRGBColorValue(); + CSSPrimitiveValue val; + val = col.getRed(); + float red = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getGreen(); + float green = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getBlue(); + float blue = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + color = new PDFColor(red, green, blue); + } + } + currentStream.write(color.getColorSpaceOut(fill)); + if (fill) + di.fill = true; + else + di.stroke = true; + return; + } + Hashtable table = null; + Vector someColors = new Vector(); + Vector theCoords = null; + Vector theBounds = new Vector(); + // the coords should be relative to the current object + // check value types, eg. % + if (gradUnits == SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE) { + if (area instanceof SVGTransformable) { + SVGTransformable tf = (SVGTransformable) area; + double x1, y1, x2, y2; + x1 = acx.getBaseVal().getValue(); + y1 = -acy.getBaseVal().getValue(); + x2 = afx.getBaseVal().getValue(); + y2 = -afy.getBaseVal().getValue(); + SVGMatrix matrix = tf.getScreenCTM(); + double oldx = x1; + x1 = matrix.getA() * x1 + matrix.getB() * y1 + + matrix.getE(); + y1 = matrix.getC() * oldx + matrix.getD() * y1 + + matrix.getF(); + oldx = x2; + x2 = matrix.getA() * x2 + matrix.getB() * y2 + + matrix.getE(); + y2 = matrix.getC() * oldx + matrix.getD() * y2 + + matrix.getF(); + theCoords = new Vector(); + // if(spread == SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { + // } else if(spread== SVGGradientElement.SVG_SPREADMETHOD_REFLECT) { + // } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + x1)); + // the y val needs to be adjust by 2 * R * rotation + // depending on if this value is from an x or y coord + // before transformation + theCoords.addElement( + new Double(currentYPosition / 1000f - y1 + + (matrix.getC() - matrix.getD()) * 2 * + ar.getBaseVal().getValue())); + theCoords.addElement(new Double(0)); + theCoords.addElement( + new Double(currentXPosition / 1000f + x2)); + theCoords.addElement( + new Double(currentYPosition / 1000f - y2 + + (matrix.getC() - matrix.getD()) * 2 * + ar.getBaseVal().getValue())); + theCoords.addElement( + new Double(ar.getBaseVal().getValue())); + // } + } + } else if (gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && + area instanceof GraphicElement) { + SVGRect rect = ((GraphicElement) area).getBBox(); + if (rect != null) { + theCoords = new Vector(); + SVGLength val; + val = acx.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentXPosition / 1000f + + rect.getX() + + val.getValue() * rect.getWidth())); + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + + val.getValue())); + } + val = acy.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentYPosition / 1000f - + rect.getY() - + val.getValue() * rect.getHeight())); + } else { + theCoords.addElement( + new Double(currentYPosition / 1000f - + val.getValue())); + } + theCoords.addElement(new Double(0)); + val = afx.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentXPosition / 1000f + + rect.getX() + + val.getValue() * rect.getWidth())); + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + + val.getValue())); + } + val = afy.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentYPosition / 1000f - + rect.getY() - + val.getValue() * rect.getHeight())); + } else { + theCoords.addElement( + new Double(currentYPosition / 1000f - + val.getValue())); + } + val = ar.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(val.getValue() * rect.getHeight())); + } else { + theCoords.addElement(new Double(val.getValue())); + } + } + } + if (theCoords == null) { + // percentage values are expressed according to the viewport. + SVGElement vp = + ((GraphicElement) area).getNearestViewportElement(); + if (area instanceof GraphicElement) { + SVGRect rect = ((GraphicElement) area).getBBox(); + if (rect != null) { + theCoords = new Vector(); + SVGLength val = acx.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || + gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentXPosition / 1000f + + rect.getX() + + val.getValue() * rect.getWidth())); + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + + val.getValue())); + } + val = acy.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || + gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentYPosition / 1000f - + rect.getY() - + val.getValue() * rect.getHeight())); + } else { + theCoords.addElement( + new Double(currentYPosition / 1000f - + val.getValue())); + } + theCoords.addElement(new Double(0)); + val = afx.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || + gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentXPosition / 1000f + + rect.getX() + + val.getValue() * rect.getWidth())); + } else { + theCoords.addElement( + new Double(currentXPosition / 1000f + + val.getValue())); + } + val = afy.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || + gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( + new Double(currentYPosition / 1000f - + rect.getY() - + val.getValue() * rect.getHeight())); + } else { + theCoords.addElement( + new Double(currentYPosition / 1000f - + val.getValue())); + } + val = ar.getBaseVal(); + if (val.getUnitType() == + SVGLength.SVG_LENGTHTYPE_PERCENTAGE || + gradUnits == + SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + theCoords.addElement( new Double(val.getValue() * + rect.getHeight())); + } else { + theCoords.addElement(new Double(val.getValue())); + } + } + } + } + if (theCoords == null) { + theCoords = new Vector(); + theCoords.addElement( new Double(currentXPosition / 1000f + + acx.getBaseVal().getValue())); + theCoords.addElement( new Double(currentYPosition / 1000f - + acy.getBaseVal().getValue())); + theCoords.addElement(new Double(0)); + theCoords.addElement( new Double(currentXPosition / 1000f + + afx.getBaseVal().getValue())); // Fx + theCoords.addElement( + new Double(currentYPosition / 1000f - + afy.getBaseVal().getValue())); // Fy + theCoords.addElement( + new Double(ar.getBaseVal().getValue())); + } + float lastoffset = 0; + for (int count = 0; count < nl.getLength(); count++) { + stop = (SVGStopElementImpl) nl.item(count); + CSSValue cv = stop.getPresentationAttribute("stop-color"); + if (cv == null) { + // maybe using color + cv = stop.getPresentationAttribute("color"); + } + if (cv == null) { + // problems + MessageHandler.errorln("no stop-color or color in stop element"); + continue; + } + PDFColor color = new PDFColor(0, 0, 0); + if (cv != null && + cv.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) cv).getPrimitiveType() == + CSSPrimitiveValue.CSS_RGBCOLOR) { + RGBColor col = + ((CSSPrimitiveValue) cv).getRGBColorValue(); + CSSPrimitiveValue val; + val = col.getRed(); + float red = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getGreen(); + float green = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getBlue(); + float blue = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + color = new PDFColor(red, green, blue); + } + } + float offset = stop.getOffset().getBaseVal(); + // create bounds from last to offset + lastoffset = offset; + someColors.addElement(color); + } + PDFPattern myPat = this.pdfDoc.createGradient(true, aColorSpace, + someColors, theBounds, theCoords); + + currentStream.write(myPat.getColorSpaceOut(fill)); + if (fill) + di.fill = true; + else + di.stroke = true; + } + + /* + * This sets up the style for drawing objects. + * Should only set style for elements that have changes. + * + */ + // need mask drawing + class DrawingInstruction { + boolean stroke = false; + boolean nonzero = false; // non-zero fill rule "f*", "B*" operator + boolean fill = false; + int linecap = 0; // butt + int linejoin = 0; // miter + int miterwidth = 8; + } + protected DrawingInstruction applyStyle(SVGElement area, + SVGStylable style) { + DrawingInstruction di = new DrawingInstruction(); + CSSValue sp; + sp = style.getPresentationAttribute("fill"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_RGBCOLOR) { + RGBColor col = + ((CSSPrimitiveValue) sp).getRGBColorValue(); + CSSPrimitiveValue val; + val = col.getRed(); + float red = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getGreen(); + float green = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getBlue(); + float blue = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + PDFColor fillColour = new PDFColor(red, green, blue); + currentColour = fillColour; + currentStream.write(fillColour.getColorSpaceOut(true)); + di.fill = true; + } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_URI) { + // gradient + String str = ((CSSPrimitiveValue) sp).getCssText(); + handleGradient(str, di, true, area); + } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + String str = ((CSSPrimitiveValue) sp).getCssText(); + if (str.equals("none")) { + di.fill = false; + } else if (str.equals("currentColor")) { + currentStream.write( + currentColour.getColorSpaceOut(true)); + di.fill = true; + // } else { + // handleGradient(str, true, area); + } + } + } + } else { + PDFColor fillColour = new PDFColor(0, 0, 0); + currentStream.write(fillColour.getColorSpaceOut(true)); + } + sp = style.getPresentationAttribute("fill-rule"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + if (sp.getCssText().equals("nonzero")) { + di.nonzero = true; + } + } + } + } else { + } + sp = style.getPresentationAttribute("stroke"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_RGBCOLOR) { + RGBColor col = + ((CSSPrimitiveValue) sp).getRGBColorValue(); + CSSPrimitiveValue val; + val = col.getRed(); + float red = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getGreen(); + float green = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + val = col.getBlue(); + float blue = val.getFloatValue( + CSSPrimitiveValue.CSS_NUMBER); + PDFColor fillColour = new PDFColor(red, green, blue); + currentStream.write( + fillColour.getColorSpaceOut(false)); + di.stroke = true; + } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_URI) { + // gradient + String str = ((CSSPrimitiveValue) sp).getCssText(); + handleGradient(str, di, false, area); + } else if ( ((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + String str = ((CSSPrimitiveValue) sp).getCssText(); + if (str.equals("none")) { + di.stroke = false; + // } else { + // handleGradient(str, false, area); + } + } + } + } else { + PDFColor fillColour = new PDFColor(0, 0, 0); + currentStream.write(fillColour.getColorSpaceOut(false)); + } + sp = style.getPresentationAttribute("stroke-linecap"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + String str = sp.getCssText(); + // butt, round ,square + if (str.equals("butt")) { + currentStream.write(0 + " J\n"); + } else if (str.equals("round")) { + currentStream.write(1 + " J\n"); + } else if (str.equals("square")) { + currentStream.write(2 + " J\n"); + } + } + } + } else { + } + sp = style.getPresentationAttribute("stroke-linejoin"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + String str = sp.getCssText(); + if (str.equals("miter")) { + currentStream.write(0 + " j\n"); + } else if (str.equals("round")) { + currentStream.write(1 + " j\n"); + } else if (str.equals("bevel")) { + currentStream.write(2 + " j\n"); + } + } + } + } else { + } + sp = style.getPresentationAttribute("stroke-miterlimit"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + float width; + width = ((CSSPrimitiveValue) sp).getFloatValue( + CSSPrimitiveValue.CSS_PT); + PDFNumber pdfNumber = new PDFNumber(); + currentStream.write(pdfNumber.doubleOut(width) + " M\n"); + } + } else { + } + sp = style.getPresentationAttribute("stroke-width"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + float width; + width = ((CSSPrimitiveValue) sp).getFloatValue( + CSSPrimitiveValue.CSS_PT); + PDFNumber pdfNumber = new PDFNumber(); + currentStream.write(pdfNumber.doubleOut(width) + " w\n"); + } + } + sp = style.getPresentationAttribute("stroke-dasharray"); + if (sp != null) { + if (sp.getValueType() == CSSValue.CSS_VALUE_LIST) { + currentStream.write("[ "); + CSSValueList list = (CSSValueList) sp; + for (int count = 0; count < list.getLength(); count++) { + CSSValue val = list.item(count); + if (val.getValueType() == + CSSValue.CSS_PRIMITIVE_VALUE) { + currentStream.write( + ((CSSPrimitiveValue) val).getFloatValue( + CSSPrimitiveValue.CSS_NUMBER) + " "); + } + } + currentStream.write("] "); + sp = style.getPresentationAttribute("stroke-dashoffset"); + if (sp != null && sp.getValueType() == + CSSValue.CSS_PRIMITIVE_VALUE) { + currentStream.write( + ((CSSPrimitiveValue) sp).getFloatValue( + CSSPrimitiveValue.CSS_NUMBER) + " d\n"); + } else { + currentStream.write("0 d\n"); + } + } + } + sp = style.getPresentationAttribute("clip-path"); + if (sp != null) { + String clipurl; + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_URI) { + clipurl = ((CSSPrimitiveValue) sp).getCssText(); + if (clipurl.startsWith("url(")) { + int b1 = clipurl.indexOf("("); + int b2 = clipurl.indexOf(")"); + clipurl = clipurl.substring(b1 + 1, b2); + } + // get def of mask and set mask + SVGElement graph = null; + graph = locateDef(clipurl, area); + if (graph != null) { + MessageHandler.logln("clip path: " + graph); + // render the clip path elements and make it the clip + // renderElement(svgarea, graph, posx, posy); + } + } + } + } + sp = style.getPresentationAttribute("mask"); + if (sp != null) { + String maskurl; + if (sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_URI) { + maskurl = ((CSSPrimitiveValue) sp).getCssText(); + // System.out.println("mask: " + maskurl); + // get def of mask and set mask + if (maskurl.startsWith("url(")) { + int b1 = maskurl.indexOf("("); + int b2 = maskurl.indexOf(")"); + maskurl = maskurl.substring(b1 + 1, b2); + } + SVGElement graph = null; + graph = locateDef(maskurl, area); + if (graph != null) { + MessageHandler.logln("mask: " + graph); + // SVGElement parent = graph.getGraphicParent(); + // graph.setParent(area); + // renderElement(svgarea, graph, posx, posy); + // graph.setParent(parent); + } + } + } + } + return di; + } + + protected void applyTransform(SVGAnimatedTransformList trans) { + PDFNumber pdfNumber = new PDFNumber(); + SVGTransformList list = trans.getBaseVal(); + for (int count = 0; count < list.getNumberOfItems(); count++) { + SVGMatrix matrix = + ((SVGTransform) list.getItem(count)).getMatrix(); + currentStream.write(pdfNumber.doubleOut(matrix.getA()) + + " " + pdfNumber.doubleOut(matrix.getB()) + " " + + pdfNumber.doubleOut(matrix.getC()) + " " + + pdfNumber.doubleOut(matrix.getD()) + " " + + pdfNumber.doubleOut(matrix.getE()) + " " + + pdfNumber.doubleOut(matrix.getF()) + " cm\n"); + } + } + + /** + * Main rendering selection. + * This applies any transform and style and then calls the appropriate + * rendering method depending on the type of element. + */ + public void renderElement(SVGElement area, int posx, int posy) { + int x = posx; + int y = posy; + // CSSStyleDeclaration style = null; + // if(area instanceof SVGStylable) + // style = ((SVGStylable)area).getStyle(); + DrawingInstruction di = null; + + currentStream.write("q\n"); + if (area instanceof SVGTransformable) { + SVGTransformable tf = (SVGTransformable) area; + SVGAnimatedTransformList trans = tf.getTransform(); + if (trans != null) { + applyTransform(trans); + } + } + + if (area instanceof SVGStylable) { + di = applyStyle(area, (SVGStylable) area); + } + + if (area instanceof SVGRectElement) { + SVGRectElement rg = (SVGRectElement) area; + float rectx = rg.getX().getBaseVal().getValue(); + float recty = rg.getY().getBaseVal().getValue(); + float rx = rg.getRx().getBaseVal().getValue(); + float ry = rg.getRy().getBaseVal().getValue(); + float rw = rg.getWidth().getBaseVal().getValue(); + float rh = rg.getHeight().getBaseVal().getValue(); + addRect(rectx, recty, rw, rh, rx, ry, di); + } else if (area instanceof SVGLineElement) { + SVGLineElement lg = (SVGLineElement) area; + float x1 = lg.getX1().getBaseVal().getValue(); + float y1 = lg.getY1().getBaseVal().getValue(); + float x2 = lg.getX2().getBaseVal().getValue(); + float y2 = lg.getY2().getBaseVal().getValue(); + addLine(x1, y1, x2, y2, di); + } else if (area instanceof SVGTextElementImpl) { + // currentStream.add("q\n"); + // currentStream.add(1 + " " + 0 + " " + 0 + " " + 1 + " " + 0 + " " + 0 + " cm\n"); + currentStream.write("BT\n"); + renderText((SVGTextElementImpl) area, 0, 0, di); + currentStream.write("ET\n"); + // currentStream.add("Q\n"); + } else if (area instanceof SVGCircleElement) { + SVGCircleElement cg = (SVGCircleElement) area; + float cx = cg.getCx().getBaseVal().getValue(); + float cy = cg.getCy().getBaseVal().getValue(); + float r = cg.getR().getBaseVal().getValue(); + addCircle(cx, cy, r, di); + } else if (area instanceof SVGEllipseElement) { + SVGEllipseElement cg = (SVGEllipseElement) area; + float cx = cg.getCx().getBaseVal().getValue(); + float cy = cg.getCy().getBaseVal().getValue(); + float rx = cg.getRx().getBaseVal().getValue(); + float ry = cg.getRy().getBaseVal().getValue(); + addEllipse(cx, cy, rx, ry, di); + } else if (area instanceof SVGPathElementImpl) { + addPath(((SVGPathElementImpl) area).pathElements, posx, + posy, di); + } else if (area instanceof SVGPolylineElementImpl) { + addPolyline(((SVGPolylineElementImpl) area).points, di, false); + } else if (area instanceof SVGPolygonElementImpl) { + addPolyline(((SVGPolygonElementImpl) area).points, di, true); + } else if (area instanceof SVGGElementImpl) { + renderGArea((SVGGElementImpl) area, x, y); + } else if (area instanceof SVGUseElementImpl) { + SVGUseElementImpl ug = (SVGUseElementImpl) area; + String ref = ug.link; + // ref = ref.substring(1, ref.length()); + SVGElement graph = null; + graph = locateDef(ref, ug); + if (graph != null) { + // probably not the best way to do this, should be able + // to render without the style being set. + // SVGElement parent = graph.getGraphicParent(); + // graph.setParent(area); + // need to clip (if necessary) to the use area + // the style of the linked element is as if it was + // a direct descendant of the use element. + + // scale to the viewBox + + if (graph instanceof SVGSymbolElement) { + currentStream.write("q\n"); + SVGSymbolElement symbol = (SVGSymbolElement) graph; + SVGRect view = symbol.getViewBox().getBaseVal(); + float usex = ug.getX().getBaseVal().getValue(); + float usey = ug.getY().getBaseVal().getValue(); + float usewidth = ug.getWidth().getBaseVal().getValue(); + float useheight = + ug.getHeight().getBaseVal().getValue(); + float scaleX; + float scaleY; + scaleX = usewidth / view.getWidth(); + scaleY = useheight / view.getHeight(); + currentStream.write(usex + " " + usey + " m\n"); + currentStream.write((usex + usewidth) + " " + + usey + " l\n"); + currentStream.write((usex + usewidth) + " " + + (usey + useheight) + " l\n"); + currentStream.write(usex + " " + + (usey + useheight) + " l\n"); + currentStream.write("h\n"); + currentStream.write("W\n"); + currentStream.write("n\n"); + currentStream.write(scaleX + " 0 0 " + scaleY + + " " + usex + " " + usey + " cm\n"); + renderSymbol(symbol, posx, posy); + currentStream.write("Q\n"); + } else { + renderElement(graph, posx, posy); + } + // graph.setParent(parent); + } + else { + MessageHandler.logln("Use Element: " + ref + " not found"); + } + } else if (area instanceof SVGImageElementImpl) { + SVGImageElementImpl ig = (SVGImageElementImpl) area; + renderImage(ig.link, ig.x, ig.y, ig.width, ig.height); + } else if (area instanceof SVGSVGElement) { + currentStream.write("q\n"); + SVGSVGElement svgel = (SVGSVGElement) area; + float svgx = 0; + if (svgel.getX() != null) + svgx = svgel.getX().getBaseVal().getValue(); + float svgy = 0; + if (svgel.getY() != null) + svgy = svgel.getY().getBaseVal().getValue(); + currentStream.write(1 + " 0 0 " + 1 + " " + svgx + " " + + svgy + " cm\n"); + renderSVG(svgel, (int)(x + 1000 * svgx), + (int)(y + 1000 * svgy)); + currentStream.write("Q\n"); + // } else if (area instanceof SVGSymbolElement) { + // 'symbol' element is not rendered (except by 'use') + } else if (area instanceof SVGAElement) { + SVGAElement ael = (SVGAElement) area; + org.w3c.dom.NodeList nl = ael.getChildNodes(); + for (int count = 0; count < nl.getLength(); count++) { + org.w3c.dom.Node n = nl.item(count); + if (n instanceof SVGElement) { + if (n instanceof GraphicElement) { + SVGRect rect = ((GraphicElement) n).getBBox(); + if (rect != null) { + /* currentAnnotList = this.pdfDoc.makeAnnotList(); + currentPage.setAnnotList(currentAnnotList); + String dest = linkSet.getDest(); + int linkType = linkSet.getLinkType(); + currentAnnotList.addLink( + this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType)); + currentAnnotList = null; + */ } + } + renderElement((SVGElement) n, posx, posy); + } + } + } else if (area instanceof SVGSwitchElement) { + handleSwitchElement(posx, posy, (SVGSwitchElement) area); + } + // should be done with some cleanup code, so only + // required values are reset. + currentStream.write("Q\n"); + } + + /** + * Todo: underline, linethrough, textpath + */ + public void renderText(SVGTextElementImpl tg, float x, float y, + DrawingInstruction di) { + SVGTextRenderer str = new SVGTextRenderer(fontState, tg, x, y); + if (di.fill) { + if (di.stroke) { + currentStream.write("2 Tr\n"); + } else { + currentStream.write("0 Tr\n"); + } + } else if (di.stroke) { + currentStream.write("1 Tr\n"); + } + str.renderText(tg); + } + + /** + * Adds an svg string to the output. + * This handles the escaping of special pdf chars and deals with + * whitespace. + */ + protected float addSVGStr(FontState fs, float currentX, String str, + boolean spacing) { + boolean inbetween = false; + boolean addedspace = false; + StringBuffer pdf = new StringBuffer(); + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + if (ch > 127) { + pdf = pdf.append("\\"); + pdf = pdf.append(Integer.toOctalString((int) ch)); + currentX += fs.width(ch) / 1000f; + inbetween = true; + addedspace = false; + } else { + switch (ch) { + case '(' : + pdf = pdf.append("\\("); + currentX += fs.width(ch) / 1000f; + inbetween = true; + addedspace = false; + break; + case ')' : + pdf = pdf.append("\\)"); + currentX += fs.width(ch) / 1000f; + inbetween = true; + addedspace = false; + break; + case '\\' : + pdf = pdf.append("\\\\"); + currentX += fs.width(ch) / 1000f; + inbetween = true; + addedspace = false; + break; + case '\t': + case ' ': + if (spacing) { + pdf = pdf.append(' '); + currentX += fs.width(' ') / 1000f; + } else { + if (inbetween && !addedspace) { + addedspace = true; + pdf = pdf.append(' '); + currentX += fs.width(' ') / 1000f; + } + } + break; + case '\n': + case '\r': + if (spacing) { + pdf = pdf.append(' '); + currentX += fs.width(' ') / 1000f; + } + break; + default: + addedspace = false; + pdf = pdf.append(ch); + currentX += fs.width(ch) / 1000f; + inbetween = true; + break; + } + } + } + currentStream.write(pdf.toString()); + return currentX; + } + + /** + * Locates a defined element in an svg document. + * Either gets the element defined by its "id" in the current + * SVGDocument, or if the uri reference is to an external + * document it loads the document and returns the element. + */ + protected SVGElement locateDef(String ref, SVGElement currentElement) { + int pos; + ref = ref.trim(); + pos = ref.indexOf("#"); + if (pos == 0) { + // local doc + Document doc = currentElement.getOwnerDocument(); + Element ele = + doc.getElementById(ref.substring(1, ref.length())); + if (ele instanceof SVGElement) { + return (SVGElement) ele; + } + } else if (pos != -1) { + String href = ref.substring(0, pos); + if (href.indexOf(":") == -1) { + href = "file:" + href; + } + try { + // this is really only to get a cached svg image + FopImage img = FopImageFactory.Make(href); + if (img instanceof SVGImage) { + SVGDocument doc = ((SVGImage) img).getSVGDocument(); + Element ele = doc.getElementById( + ref.substring(pos + 1, ref.length())); + if (ele instanceof SVGElement) { + return (SVGElement) ele; + } + } + } catch (Exception e) { + MessageHandler.errorln(e.toString()); + } + } + return null; + } + + /** + * This class is used to handle the rendering of svg text. + * This is so that it can deal with the recursive rendering + * of text markup, while keeping track of the state and position. + */ + class SVGTextRenderer { + FontState fs; + String transstr; + float currentX; + float currentY; + float baseX; + float baseY; + SVGMatrix matrix; + float x; + float y; + + SVGTextRenderer(FontState fontState, SVGTextElementImpl tg, + float x, float y) { + fs = fontState; + + PDFNumber pdfNumber = new PDFNumber(); + SVGTransformList trans = tg.getTransform().getBaseVal(); + matrix = trans.consolidate().getMatrix(); + transstr = (pdfNumber.doubleOut(matrix.getA()) + " " + + pdfNumber.doubleOut(matrix.getB()) + " " + + pdfNumber.doubleOut(matrix.getC()) + " " + + pdfNumber.doubleOut(-matrix.getD()) + " "); + this.x = x; + this.y = y; + } + + void renderText(SVGTextElementImpl te) { + DrawingInstruction di = applyStyle(te, te); + if (di.fill) { + if (di.stroke) { + currentStream.write("2 Tr\n"); + } else { + currentStream.write("0 Tr\n"); + } + } else if (di.stroke) { + currentStream.write("1 Tr\n"); + } + updateFont(te, fs); + + float tx = te.x; + float ty = te.y; + currentX = x + tx; + currentY = y + ty; + baseX = currentX; + baseY = currentY; + NodeList nodel = te.getChildNodes(); + // Vector list = te.textList; + for (int count = 0; count < nodel.getLength(); count++) { + Object o = nodel.item(count); + applyStyle(te, te); + if (o instanceof CharacterData) { + String str = ((CharacterData) o).getData(); + currentStream.write(transstr + + (currentX + matrix.getE()) + " " + + (baseY + matrix.getF()) + " Tm " + "("); + boolean spacing = "preserve".equals(te.getXMLspace()); + currentX = addSVGStr(fs, currentX, str, spacing); + currentStream.write(") Tj\n"); + } else if (o instanceof SVGTextPathElementImpl) { + SVGTextPathElementImpl tpg = (SVGTextPathElementImpl) o; + String ref = tpg.str; + SVGElement graph = null; + graph = locateDef(ref, tpg); + if (graph instanceof SVGPathElementImpl) { + // probably not the best way to do this, should be able + // to render without the style being set. + // GraphicImpl parent = graph.getGraphicParent(); + // graph.setParent(tpg); + // set text path?? + // how should this work + // graph.setParent(parent); + } + } else if (o instanceof SVGTRefElementImpl) { + SVGTRefElementImpl trg = (SVGTRefElementImpl) o; + String ref = trg.ref; + SVGElement element = locateDef(ref, trg); + if (element instanceof SVGTextElementImpl) { + // GraphicImpl parent = graph.getGraphicParent(); + // graph.setParent(trg); + SVGTextElementImpl tele = + (SVGTextElementImpl) element; + // the style should be from tele, but it needs to be placed as a child + // of trg to work + di = applyStyle(trg, trg); + if (di.fill) { + if (di.stroke) { + currentStream.write("2 Tr\n"); + } else { + currentStream.write("0 Tr\n"); + } + } else if (di.stroke) { + currentStream.write("1 Tr\n"); + } + boolean changed = false; + FontState oldfs = fs; + changed = updateFont(te, fs); + NodeList nl = tele.getChildNodes(); + boolean spacing = + "preserve".equals(trg.getXMLspace()); + renderTextNodes(spacing, nl, + trg.getX().getBaseVal(), + trg.getY().getBaseVal(), + trg.getDx().getBaseVal(), + trg.getDy().getBaseVal()); + + if (changed) { + fs = oldfs; + currentStream.write("/" + + fs.getFontName() + " " + + fs.getFontSize() / 1000f + " Tf\n"); + } + // graph.setParent(parent); + } + } else if (o instanceof SVGTSpanElementImpl) { + SVGTSpanElementImpl tsg = (SVGTSpanElementImpl) o; + applyStyle(tsg, tsg); + boolean changed = false; + FontState oldfs = fs; + changed = updateFont(tsg, fs); + boolean spacing = "preserve".equals(tsg.getXMLspace()); + renderTextNodes(spacing, tsg.getChildNodes(), + tsg.getX().getBaseVal(), + tsg.getY().getBaseVal(), + tsg.getDx().getBaseVal(), + tsg.getDy().getBaseVal()); + + // currentX += fs.width(' ') / 1000f; + if (changed) { + fs = oldfs; + currentStream.write("/" + fs.getFontName() + + " " + fs.getFontSize() / 1000f + " Tf\n"); + } + } else { + MessageHandler.errorln("Error: unknown text element " + o); + } + } + } + + void renderTextNodes(boolean spacing, NodeList nl, + SVGLengthList xlist, SVGLengthList ylist, + SVGLengthList dxlist, SVGLengthList dylist) { + boolean inbetween = false; + boolean addedspace = false; + int charPos = 0; + float xpos = currentX; + float ypos = currentY; + + for (int count = 0; count < nl.getLength(); count++) { + Node n = nl.item(count); + if (n instanceof CharacterData) { + StringBuffer pdf = new StringBuffer(); + String str = ((CharacterData) n).getData(); + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + xpos = currentX; + ypos = currentY; + if (ylist.getNumberOfItems() > charPos) { + ypos = baseY + (ylist.getItem(charPos)). + getValue(); + } + if (dylist.getNumberOfItems() > charPos) { + ypos = ypos + (dylist.getItem(charPos)). + getValue(); + } + if (xlist.getNumberOfItems() > charPos) { + xpos = baseX + (xlist.getItem(charPos)). + getValue(); + } + if (dxlist.getNumberOfItems() > charPos) { + xpos = xpos + (dxlist.getItem(charPos)). + getValue(); + } + if (ch > 127) { + pdf = pdf.append(transstr + + (xpos + matrix.getE()) + " " + + (ypos + matrix.getF()) + " Tm " + + "(" + "\\" + + Integer.toOctalString((int) ch) + + ") Tj\n"); + currentX = xpos + fs.width(ch) / 1000f; + currentY = ypos; + charPos++; + inbetween = true; + addedspace = false; + } else { + switch (ch) { + case '(' : + pdf = pdf.append(transstr + + (xpos + matrix.getE()) + + " " + (ypos + + matrix.getF()) + " Tm " + + "(" + "\\(" + ") Tj\n"); + currentX = xpos + fs.width(ch) / 1000f; + currentY = ypos; + charPos++; + inbetween = true; + addedspace = false; + break; + case ')' : + pdf = pdf.append(transstr + + (xpos + matrix.getE()) + + " " + (ypos + + matrix.getF()) + " Tm " + + "(" + "\\)" + ") Tj\n"); + currentX = xpos + fs.width(ch) / 1000f; + currentY = ypos; + charPos++; + inbetween = true; + addedspace = false; + break; + case '\\' : + pdf = pdf.append(transstr + + (xpos + matrix.getE()) + + " " + (ypos + + matrix.getF()) + " Tm " + + "(" + "\\\\" + ") Tj\n"); + currentX = xpos + fs.width(ch) / 1000f; + currentY = ypos; + charPos++; + inbetween = true; + addedspace = false; + break; + case '\t': + case ' ': + if (spacing) { + currentX = xpos + fs.width(' ') / + 1000f; + currentY = ypos; + charPos++; + } else { + if (inbetween && !addedspace) { + addedspace = true; + currentX = xpos + fs.width(' ') + / 1000f; + currentY = ypos; + charPos++; + } + } + break; + case '\n': + case '\r': + if (spacing) { + currentX = xpos + fs.width(' ') / + 1000f; + currentY = ypos; + charPos++; + } + break; + default: + addedspace = false; + pdf = pdf.append(transstr + + (xpos + matrix.getE()) + + " " + (ypos + + matrix.getF()) + " Tm " + + "(" + ch + ") Tj\n"); + currentX = xpos + fs.width(ch) / 1000f; + currentY = ypos; + charPos++; + inbetween = true; + break; + } + } + currentStream.write(pdf.toString()); + } + } + } + } + + protected boolean updateFont(SVGStylable style, FontState fs) { + boolean changed = false; + String fontFamily = fs.getFontFamily(); + CSSValue sp = style.getPresentationAttribute("font-family"); + if (sp != null && + sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + fontFamily = sp.getCssText(); + } + } + if (!fontFamily.equals(fs.getFontFamily())) { + changed = true; + } + String fontStyle = fs.getFontStyle(); + sp = style.getPresentationAttribute("font-style"); + if (sp != null && + sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + fontStyle = sp.getCssText(); + } + } + if (!fontStyle.equals(fs.getFontStyle())) { + changed = true; + } + String fontWeight = fs.getFontWeight(); + sp = style.getPresentationAttribute("font-weight"); + if (sp != null && + sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if (((CSSPrimitiveValue) sp).getPrimitiveType() == + CSSPrimitiveValue.CSS_STRING) { + fontWeight = sp.getCssText(); + } + } + if (!fontWeight.equals(fs.getFontWeight())) { + changed = true; + } + float newSize = fs.getFontSize() / 1000f; + sp = style.getPresentationAttribute("font-size"); + if (sp != null && + sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + // if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_NUMBER) { + newSize = ((CSSPrimitiveValue) sp).getFloatValue( + CSSPrimitiveValue.CSS_PT); + // } + } + if (fs.getFontSize() / 1000f != newSize) { + changed = true; + } + if (changed) { + try { + // FIX-ME: should get the font-variant property + fs = new FontState(fs.getFontInfo(), fontFamily, + fontStyle, fontWeight, (int)(newSize * 1000), + FontVariant.NORMAL); + } catch (Exception fope) { + } + this.fs = fs; + + currentStream.write("/" + fs.getFontName() + " " + + newSize + " Tf\n"); + } else { + if (!currentFontName.equals(fs.getFontName()) || + currentFontSize != fs.getFontSize()) { + // currentFontName = fs.getFontName(); + // currentFontSize = fs.getFontSize(); + currentStream.write("/" + fs.getFontName() + " " + + (fs.getFontSize() / 1000) + " Tf\n"); + } + } + return changed; + } + } } diff --git a/src/org/apache/fop/svg/SVG.java b/src/org/apache/fop/svg/SVG.java index b67b8c04e..1d52fed3b 100644 --- a/src/org/apache/fop/svg/SVG.java +++ b/src/org/apache/fop/svg/SVG.java @@ -1,35 +1,35 @@ /*-- $Id$ -- ============================================================================ - The Apache Software License, Version 1.1 + The Apache Software License, Version 1.1 ============================================================================ - Copyright (C) 1999 The Apache Software Foundation. All rights reserved. + Copyright (C) 1999 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. + this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must - include the following acknowledgment: "This product includes software - developed by the Apache Software Foundation (http://www.apache.org/)." - Alternately, this acknowledgment may appear in the software itself, if - and wherever such third-party acknowledgments normally appear. + include the following acknowledgment: "This product includes software + developed by the Apache Software Foundation (http://www.apache.org/)." + Alternately, this acknowledgment may appear in the software itself, if + and wherever such third-party acknowledgments normally appear. 4. The names "FOP" and "Apache Software Foundation" must not be used to - endorse or promote products derived from this software without prior - written permission. For written permission, please contact - apache@apache.org. + endorse or promote products derived from this software without prior + written permission. For written permission, please contact + apache@apache.org. 5. Products derived from this software may not be called "Apache", nor may - "Apache" appear in their name, without prior written permission of the - Apache Software Foundation. + "Apache" appear in their name, without prior written permission of the + Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND @@ -69,174 +69,175 @@ import org.apache.fop.dom.svg.SVGArea; */ public class SVG extends FObj implements GraphicsCreator { - /** - * inner class for making SVG objects. - */ - public static class Maker extends FObj.Maker { - - /** - * make an SVG object. - * - * @param parent the parent formatting object - * @param propertyList the explicit properties of this object - * - * @return the SVG object - */ - public FObj make(FObj parent, - PropertyList propertyList) throws FOPException { - return new SVG(parent, propertyList); - } - } - - /** - * returns the maker for this object. - * - * @return the maker for SVG objects - */ - public static FObj.Maker maker() { - return new SVG.Maker(); - } - - FontState fs; - float width; - float height; - - /** - * constructs an SVG object (called by Maker). - * - * @param parent the parent formatting object - * @param propertyList the explicit properties of this object - */ - public SVG(FObj parent, PropertyList propertyList) { - super(parent, propertyList); - this.name = "svg:svg"; - } - - public SVGElement createGraphic() { - SVGSVGElementImpl svgArea = null; - SVGLength w = ((SVGLengthProperty) this.properties.get("width")). - getSVGLength(); - SVGLength h = ((SVGLengthProperty) this.properties.get("height")). - getSVGLength(); - svgArea = new SVGSVGElementImpl(); - SVGAnimatedLengthImpl sal; - if (w == null) - w = new SVGLengthImpl(); - sal = new SVGAnimatedLengthImpl(w); - sal.setBaseVal(w); - svgArea.setWidth(sal); - if (h == null) - h = new SVGLengthImpl(); - sal = new SVGAnimatedLengthImpl(h); - sal.setBaseVal(h); - svgArea.setHeight(sal); - SVGLength lengthProp = - ((SVGLengthProperty) this.properties.get("x")). - getSVGLength(); - SVGLength x = lengthProp == null ? new SVGLengthImpl() : lengthProp; - sal = new SVGAnimatedLengthImpl(x); - sal.setBaseVal(x); - svgArea.setX(sal); - lengthProp = ((SVGLengthProperty) this.properties.get("y")). - getSVGLength(); - SVGLength y = lengthProp == null ? new SVGLengthImpl() : lengthProp; - sal = new SVGAnimatedLengthImpl(y); - sal.setBaseVal(y); - svgArea.setY(sal); - - svgArea.setStyle( - ((SVGStyle) this.properties.get("style")).getStyle()); - svgArea.setTransform( - ((SVGTransform) this.properties.get("transform")). - getTransform()); - svgArea.setId(this.properties.get("id").getString()); - int numChildren = this.children.size(); - for (int i = 0; i < numChildren; i++) { - FONode fo = (FONode) children.elementAt(i); - if (fo instanceof GraphicsCreator) { - SVGElement impl = ((GraphicsCreator) fo).createGraphic(); - if (impl != null) { - if (impl instanceof SVGElementImpl) - ((SVGElementImpl) impl).setClassName( - new SVGAnimatedStringImpl( - ((FObj) fo).getProperty( - "class").getString())); - svgArea.appendChild((org.w3c.dom.Node) impl); - } - // } else if(fo instanceof Defs) { - // svgArea.addDefs(((Defs)fo).createDefs()); - } - Status status; - } - return svgArea; - } - - /** - * layout this formatting object. - * - * @param area the area to layout the object into - * - * @return the status of the layout - */ - public Status layout(Area area) throws FOPException { - - if (!(area instanceof ForeignObjectArea)) { - // this is an error - throw new FOPException("SVG not in fo:instream-foreign-object"); - } - - if (this.marker == BREAK_AFTER) { - return new Status(Status.OK); - } - - if (this.marker == START) { - /* retrieve properties */ - String id = this.properties.get("id").getString(); - String fontFamily = - this.properties.get("font-family").getString(); - String fontStyle = - this.properties.get("font-style").getString(); - String fontWeight = - this.properties.get("font-weight").getString(); - int fontSize = - this.properties.get("font-size").getLength().mvalue(); - - this.fs = new FontState(area.getFontInfo(), fontFamily, - fontStyle, fontWeight, fontSize); - SVGLength length; - length = ((SVGLengthProperty) this.properties.get("width")). - getSVGLength(); - if (length == null) - length = new SVGLengthImpl(); - this.width = length.getValue(); - length = ((SVGLengthProperty) this.properties.get("height")). - getSVGLength(); - if (length == null) - length = new SVGLengthImpl(); - this.height = length.getValue(); - - this.marker = 0; - } - - /* create an SVG area */ - /* if width and height are zero, may want to get the bounds of the content. */ - SVGArea svg = new SVGArea(fs, width, height); - SVGDocument doc = new SVGDocumentImpl(); - svg.setSVGDocument(doc); - svg.start(); - - /* add the SVG area to the containing area */ - ForeignObjectArea foa = (ForeignObjectArea) area; - foa.setObject(svg); - foa.setIntrinsicWidth(svg.getWidth()); - foa.setIntrinsicHeight(svg.getHeight()); - - doc.appendChild((SVGSVGElement) createGraphic()); - - /* finish off the SVG area */ - svg.end(); - - /* return status */ - return new Status(Status.OK); - } + /** + * inner class for making SVG objects. + */ + public static class Maker extends FObj.Maker { + + /** + * make an SVG object. + * + * @param parent the parent formatting object + * @param propertyList the explicit properties of this object + * + * @return the SVG object + */ + public FObj make(FObj parent, + PropertyList propertyList) throws FOPException { + return new SVG(parent, propertyList); + } + } + + /** + * returns the maker for this object. + * + * @return the maker for SVG objects + */ + public static FObj.Maker maker() { + return new SVG.Maker(); + } + + FontState fs; + float width; + float height; + + /** + * constructs an SVG object (called by Maker). + * + * @param parent the parent formatting object + * @param propertyList the explicit properties of this object + */ + public SVG(FObj parent, PropertyList propertyList) { + super(parent, propertyList); + this.name = "svg:svg"; + } + + public SVGElement createGraphic() { + SVGSVGElementImpl svgArea = null; + SVGLength w = ((SVGLengthProperty) this.properties.get("width")). + getSVGLength(); + SVGLength h = ((SVGLengthProperty) this.properties.get("height")). + getSVGLength(); + svgArea = new SVGSVGElementImpl(); + SVGAnimatedLengthImpl sal; + if (w == null) + w = new SVGLengthImpl(); + sal = new SVGAnimatedLengthImpl(w); + sal.setBaseVal(w); + svgArea.setWidth(sal); + if (h == null) + h = new SVGLengthImpl(); + sal = new SVGAnimatedLengthImpl(h); + sal.setBaseVal(h); + svgArea.setHeight(sal); + SVGLength lengthProp = + ((SVGLengthProperty) this.properties.get("x")). + getSVGLength(); + SVGLength x = lengthProp == null ? new SVGLengthImpl() : lengthProp; + sal = new SVGAnimatedLengthImpl(x); + sal.setBaseVal(x); + svgArea.setX(sal); + lengthProp = ((SVGLengthProperty) this.properties.get("y")). + getSVGLength(); + SVGLength y = lengthProp == null ? new SVGLengthImpl() : lengthProp; + sal = new SVGAnimatedLengthImpl(y); + sal.setBaseVal(y); + svgArea.setY(sal); + + svgArea.setStyle( + ((SVGStyle) this.properties.get("style")).getStyle()); + svgArea.setTransform( + ((SVGTransform) this.properties.get("transform")). + getTransform()); + svgArea.setId(this.properties.get("id").getString()); + int numChildren = this.children.size(); + for (int i = 0; i < numChildren; i++) { + FONode fo = (FONode) children.elementAt(i); + if (fo instanceof GraphicsCreator) { + SVGElement impl = ((GraphicsCreator) fo).createGraphic(); + if (impl != null) { + if (impl instanceof SVGElementImpl) + ((SVGElementImpl) impl).setClassName( + new SVGAnimatedStringImpl( + ((FObj) fo).getProperty( + "class").getString())); + svgArea.appendChild((org.w3c.dom.Node) impl); + } + // } else if(fo instanceof Defs) { + // svgArea.addDefs(((Defs)fo).createDefs()); + } + Status status; + } + return svgArea; + } + + /** + * layout this formatting object. + * + * @param area the area to layout the object into + * + * @return the status of the layout + */ + public Status layout(Area area) throws FOPException { + + if (!(area instanceof ForeignObjectArea)) { + // this is an error + throw new FOPException("SVG not in fo:instream-foreign-object"); + } + + if (this.marker == BREAK_AFTER) { + return new Status(Status.OK); + } + + if (this.marker == START) { + /* retrieve properties */ + String id = this.properties.get("id").getString(); + String fontFamily = + this.properties.get("font-family").getString(); + String fontStyle = + this.properties.get("font-style").getString(); + String fontWeight = + this.properties.get("font-weight").getString(); + int fontSize = + this.properties.get("font-size").getLength().mvalue(); + + // FIX-ME: should get the font-variant property + this.fs = new FontState(area.getFontInfo(), fontFamily, + fontStyle, fontWeight, fontSize, FontVariant.NORMAL); + + SVGLength length; + length = ((SVGLengthProperty) this.properties.get("width")).getSVGLength(); + if (length == null) + length = new SVGLengthImpl(); + this.width = length.getValue(); + length = ((SVGLengthProperty) this.properties.get("height")). + getSVGLength(); + if (length == null) + length = new SVGLengthImpl(); + this.height = length.getValue(); + + this.marker = 0; + } + + /* create an SVG area */ + /* if width and height are zero, may want to get the bounds of the content. */ + SVGArea svg = new SVGArea(fs, width, height); + SVGDocument doc = new SVGDocumentImpl(); + svg.setSVGDocument(doc); + svg.start(); + + /* add the SVG area to the containing area */ + ForeignObjectArea foa = (ForeignObjectArea) area; + foa.setObject(svg); + foa.setIntrinsicWidth(svg.getWidth()); + foa.setIntrinsicHeight(svg.getHeight()); + + doc.appendChild((SVGSVGElement) createGraphic()); + + /* finish off the SVG area */ + svg.end(); + + /* return status */ + return new Status(Status.OK); + } } |