From 230c9191efa128e9d7c9afb3b3bf1f1e002948f8 Mon Sep 17 00:00:00 2001 From: Keiron Liddle Date: Tue, 29 Aug 2000 00:12:15 +0000 Subject: [PATCH] changed to handle changes to dom, styling, transform, text etc. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@193680 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/pdf/PDFRenderer.java | 2542 +++++++++-------- 1 file changed, 1397 insertions(+), 1145 deletions(-) diff --git a/src/org/apache/fop/render/pdf/PDFRenderer.java b/src/org/apache/fop/render/pdf/PDFRenderer.java index 261e22b9e..d012f267f 100644 --- a/src/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/org/apache/fop/render/pdf/PDFRenderer.java @@ -65,7 +65,9 @@ import org.apache.fop.pdf.*; import org.apache.fop.layout.*; import org.apache.fop.image.*; +import org.w3c.dom.*; import org.w3c.dom.svg.*; +import org.w3c.dom.css.*; import org.w3c.dom.svg.SVGLength; import org.apache.fop.dom.svg.*; @@ -199,87 +201,6 @@ public class PDFRenderer implements Renderer { + "Q\nBT\n"); } - /** - * 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; - str = "" + x1 + " " + y1 + " m " - + x2 + " " + y2 + " l"; - if(di != null && di.fill) - currentStream.add(str + " f\n"); // ?? - currentStream.add(str + " S\n"); - } - - protected void addCircle(float cx, float cy, float r, DrawingInstruction di) - { - String str; - str = "" + cx + " " + (cy - r) + " m\n" - + "" + (cx + 21 * r / 40f) + " " + (cy - r) + " " + (cx + r) + " " + (cy - 21 * r / 40f) + " " + (cx + r) + " " + cy + " c\n" - + "" + (cx + r) + " " + (cy + 21 * r / 40f) + " " + (cx + 21 * r / 40f) + " " + (cy + r) + " " + cx + " " + (cy + r) + " c\n" - + "" + (cx - 21 * r / 40f) + " " + (cy + r) + " " + (cx - r) + " " + (cy + 21 * r / 40f) + " " + (cx - r) + " " + cy + " c\n" - + "" + (cx - r) + " " + (cy - 21 * r / 40f) + " " + (cx - 21 * r / 40f) + " " + (cy - r) + " " + cx + " " + (cy - r) + " c\n"; - - currentStream.add(str); - doDrawing(di); - } - - protected void addEllipse(float cx, float cy, float rx, float ry, DrawingInstruction di) - { - String str; - str = "" + cx + " " + (cy - ry) + " m\n" - + "" + (cx + 21 * rx / 40f) + " " + (cy - ry) + " " + (cx + rx) + " " + (cy - 21 * ry / 40f) + " " + (cx + rx) + " " + cy + " c\n" - + "" + (cx + rx) + " " + (cy + 21 * ry / 40f) + " " + (cx + 21 * rx / 40f) + " " + (cy + ry) + " " + cx + " " + (cy + ry) + " c\n" - + "" + (cx - 21 * rx / 40f) + " " + (cy + ry) + " " + (cx - rx) + " " + (cy + 21 * ry / 40f) + " " + (cx - rx) + " " + cy + " c\n" - + "" + (cx - rx) + " " + (cy - 21 * ry / 40f) + " " + (cx - 21 * rx / 40f) + " " + (cy - ry) + " " + cx + " " + (cy - ry) + " c\n"; - currentStream.add(str); - doDrawing(di); - } - - /** - * add a filled rectangle to the current stream - * - * @param x the x position of left edge in millipoints - * @param y the y position of top edge in millipoints - * @param w the width in millipoints - * @param h the height in millipoints - * @param r the red component of edges - * @param g the green component of edges - * @param b the blue component of edges - * @param fr the red component of the fill - * @param fg the green component of the fill - * @param fb the blue component of the fill - */ - protected void addRect(float x, float y, float w, float h, float rx, float ry, DrawingInstruction di) - { - String str = ""; - if(rx == 0.0 && ry == 0.0) { - str = "" + x + " " + y + " " + w + " " + h + " re\n"; - } else { - str = "" + (x + rx) + " " + y + " m\n"; - str += "" + (x + w - rx) + " " + y + " l\n"; - str += "" + (x + w) + " " + y + " " + (x + w) + " " + y + " " + (x + w) + " " + (y + ry) + " c\n"; - str += "" + (x + w) + " " + (y + h - ry) + " l\n"; - str += "" + (x + w) + " " + (y + h) + " " + (x + w) + " " + (y + h) + " " + (x + w - rx) + " " + (y + h) + " c\n"; - str += "" + (x + rx) + " " + (y + h) + " l\n"; - str += "" + x + " " + (y + h) + " " + x + " " + (y + h) + " " + x + " " + (y + h - ry) + " c\n"; - str += "" + x + " " + (y + ry) + " l\n"; - str += "" + x + " " + y + " " + x + " " + y + " " + (x + rx) + " " + y + " c\n"; - } - currentStream.add(str); - doDrawing(di); - } - /** * add a rectangle to the current stream * @@ -319,333 +240,27 @@ public class PDFRenderer implements Renderer { + "Q\nBT\n"); } - protected void addPath(Vector points, int posx, int posy, DrawingInstruction di) - { - SVGPathSegImpl pathmoveto = null; - float lastx = 0; - float lasty = 0; - for(Enumeration e = points.elements(); e.hasMoreElements(); ) { - SVGPathSegImpl pc = (SVGPathSegImpl)e.nextElement(); - float[] vals = pc.getValues(); - float lastcx = 0; - float lastcy = 0; - switch(pc.getPathSegType()) { - case SVGPathSeg.PATHSEG_MOVETO_ABS: - pathmoveto = pc; - lastx = vals[0]; - lasty = vals[1]; - currentStream.add(lastx + " " + lasty + " m\n"); - break; - case SVGPathSeg.PATHSEG_MOVETO_REL: - if(pathmoveto == null) { - lastx = vals[0]; - lasty = vals[1]; - pathmoveto = pc; - currentStream.add(lastx + " " + lasty + " m\n"); - } else { - lastx += vals[0]; - lasty += vals[1]; - currentStream.add(lastx + " " + lasty + " l\n"); - } - break; - case SVGPathSeg.PATHSEG_LINETO_ABS: - lastx = vals[0]; - lasty = vals[1]; - currentStream.add(lastx + " " + lasty + " l\n"); - break; - case SVGPathSeg.PATHSEG_LINETO_REL: - lastx += vals[0]; - lasty += vals[1]; - currentStream.add(lastx + " " + lasty + " l\n"); - break; - case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: - lasty = vals[0]; - currentStream.add(lastx + " " + lasty + " l\n"); - break; - case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: - lasty += vals[0]; - currentStream.add(lastx + " " + lasty + " l\n"); - break; - case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: - lastx = vals[0]; - currentStream.add(lastx + " " + lasty + " l\n"); - break; - case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: - lastx += vals[0]; - currentStream.add(lastx + " " + lasty + " l\n"); - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: - lastx = vals[4]; - lasty = vals[5]; - lastcx = vals[2]; - lastcy = vals[3]; - currentStream.add((vals[0]) + " " + (vals[1]) + " " + - (vals[2]) + " " + (vals[3]) + " " + - lastx + " " + lasty + - " c\n"); - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: - currentStream.add((vals[0] + lastx) + " " + (vals[1] + lasty) + " " + - (vals[2] + lastx) + " " + (vals[3] + lasty) + " " + - (vals[4] + lastx) + " " + (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; - } - lastx = vals[2]; - lasty = vals[3]; - currentStream.add(lastcx + " " + lastcy + " " + - (vals[0]) + " " + (vals[1]) + " " + - lastx + " " + lasty + - " c\n"); - break; - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: - if(lastcx == 0) { - lastcx = lastx; - } - if(lastcy == 0) { - lastcy = lasty; - } - currentStream.add(lastcx + " " + lastcy + " " + - (vals[0] + lastx) + " " + (vals[1] + lasty) + " " + - (vals[2] + lastx) + " " + (vals[3] + lasty) + - " c\n"); - lastx += vals[2]; - lasty += vals[3]; - break; - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: - if(lastcx == 0) { - lastcx = lastx; - } - if(lastcy == 0) { - lastcy = lasty; - } - lastx = vals[0]; - lasty = vals[1]; - lastcx = 0; - lastcy = 0; - currentStream.add(lastcx + " " + lastcy + " " + - lastx + " " + lasty + - " y\n"); - break; - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: - if(lastcx == 0) { - lastcx = lastx; - } - if(lastcy == 0) { - lastcy = lasty; - } - currentStream.add(lastcx + " " + lastcy + " " + - (vals[0] + lastx) + " " + (vals[1] + lasty) + - " y\n"); - lastcx = 0; - lastcy = 0; - 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.add(contrx1 + " " + contry1 + " " + - contrx2 + " " + contry2 + " " + - vals[5] + " " + 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.add(contrx1 + " " + contry1 + " " + - contrx2 + " " + contry2 + " " + - (vals[5] + lastx) + " " + (vals[6] + lasty) + - " c\n"); - - lastcx = 0; //?? - lastcy = 0; //?? - lastx += vals[5]; - lasty += vals[6]; - } - break; - case SVGPathSeg.PATHSEG_CLOSEPATH: - currentStream.add("h\n"); - break; - } - } - doDrawing(di); - } - - protected void addPolyline(Vector points, int posx, int posy, DrawingInstruction di, boolean close) - { - 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.add(lastx + " " + lasty + " m\n"); - } - while(e.hasMoreElements()) { - pc = (PathPoint)e.nextElement(); - lastx = pc.x; - lasty = pc.y; - currentStream.add(lastx + " " + lasty + " l\n"); - } - if(close) - currentStream.add("h\n"); - doDrawing(di); - } - - protected void doDrawing(DrawingInstruction di) - { - if(di == null) { - currentStream.add("S\n"); - } else { - if(di.fill) { - if(di.stroke) { - if(!di.nonzero) - currentStream.add("B*\n"); - else - currentStream.add("B\n"); - } else { - if(!di.nonzero) - currentStream.add("f*\n"); - else - currentStream.add("f\n"); - } - } else { -// if(di.stroke) - currentStream.add("S\n"); - } - } - } - - /** - * render area container to PDF - * - * @param area the area container to render - */ - public void renderAreaContainer(AreaContainer area) { - - int saveY = this.currentYPosition; - int saveX = this.currentAreaContainerXPosition; - - if (area.getPosition() == Position.ABSOLUTE) { - // Y position is computed assuming positive Y axis, adjust for negative postscript one - this.currentYPosition = area.getYPosition() - 2 * area.getPaddingTop() - 2 * area.borderWidthTop; - this.currentAreaContainerXPosition = area.getXPosition(); - } else if (area.getPosition() == Position.RELATIVE) { - this.currentYPosition -= area.getYPosition(); - this.currentAreaContainerXPosition += area.getXPosition(); - } else if (area.getPosition() == Position.STATIC) { - this.currentYPosition -= area.getPaddingTop() + area.borderWidthTop; - this.currentAreaContainerXPosition += area.getPaddingLeft() + area.borderWidthLeft; - } + /** + * render area container to PDF + * + * @param area the area container to render + */ + public void renderAreaContainer(AreaContainer area) { + + int saveY = this.currentYPosition; + int saveX = this.currentAreaContainerXPosition; + + if (area.getPosition() == Position.ABSOLUTE) { + // Y position is computed assuming positive Y axis, adjust for negative postscript one + this.currentYPosition = area.getYPosition() - 2 * area.getPaddingTop() - 2 * area.borderWidthTop; + this.currentAreaContainerXPosition = area.getXPosition(); + } else if (area.getPosition() == Position.RELATIVE) { + this.currentYPosition -= area.getYPosition(); + this.currentAreaContainerXPosition += area.getXPosition(); + } else if (area.getPosition() == Position.STATIC) { + this.currentYPosition -= area.getPaddingTop() + area.borderWidthTop; + this.currentAreaContainerXPosition += area.getPaddingLeft() + area.borderWidthLeft; + } doFrame(area); @@ -758,28 +373,6 @@ public class PDFRenderer implements Renderer { (((float) (y - h)) / 1000f) + " cm\n" + "/Im" + xObjectNum + " Do\nQ\nBT\n"); } - - 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); - if(img != null) { - int xObjectNum = this.pdfDoc.addImage(img); - currentStream.add("q\n1 0 0 -1 " + 0 - + " " + (y + height) + " cm\n" + width + " 0 0 " + - height + " " + - x + " " + - y + " cm\n" + - "/Im" + xObjectNum + " Do\nQ\n"); -// img.close(); - } - } catch(Exception e) { - System.err.println("could not add image to SVG: " + href); - } - } /** render a foreign object area */ public void renderForeignObjectArea(ForeignObjectArea area) @@ -848,8 +441,9 @@ public class PDFRenderer implements Renderer { public void renderSVGArea(SVGArea area) { int x = this.currentAreaContainerXPosition; int y = this.currentYPosition; - int w = area.getContentWidth(); - int h = area.getHeight(); + SVGSVGElement svg = area.getSVGDocument().getRootElement(); + int w = (int)(svg.getWidth().getBaseVal().getValue() * 1000); + int h = (int)(svg.getHeight().getBaseVal().getValue() * 1000); /* * Clip to the svg area. @@ -870,48 +464,752 @@ public class PDFRenderer implements Renderer { // TODO - translate and clip to viewbox - Enumeration e = area.getChildren().elements(); - while (e.hasMoreElements()) { - Object o = e.nextElement(); - if(o instanceof GraphicImpl) { - renderElement(area, (GraphicImpl)o, x, y); - } - } + renderSVG(area.getFontState(), svg, x, y); currentStream.add("Q\n"); } - void handleGradient(String sp, boolean fill, GraphicImpl 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); - address = address.trim(); - // local reference - if(address.startsWith("#")) { - // find the gradient element - GraphicImpl gi = area.locateDef(address.substring(1, address.length())); -// System.out.println(gi + ":" + address.substring(1, address.length())); - if(gi instanceof SVGLinearGradientElement) { - SVGLinearGradientElement linear = (SVGLinearGradientElement)gi; + /** + * render inline area to PDF + * + * @param area inline area to render + */ + public void renderInlineArea(InlineArea area) { + char ch; + StringBuffer pdf = new StringBuffer(); + + String name = area.getFontState().getFontName(); + int size = area.getFontState().getFontSize(); + + PDFColor theAreaColor = new PDFColor( + (double)area.getRed(), + (double)area.getGreen(), + (double)area.getBlue() ); + + if ((!name.equals(this.currentFontName)) + || (size != this.currentFontSize)) { + this.currentFontName = name; + this.currentFontSize = size; + pdf = pdf.append("/" + name + " " + (size/1000) + " Tf\n"); + } - Vector theCoords = new Vector(); - theCoords.addElement(new Double(linear.getX1().getBaseVal().getValue())); - theCoords.addElement(new Double(linear.getY1().getBaseVal().getValue())); - theCoords.addElement(new Double(linear.getX2().getBaseVal().getValue())); - theCoords.addElement(new Double(linear.getY2().getBaseVal().getValue())); + //if (theAreaColor.isEquivalent(this.currentFill)) { + this.currentFill = theAreaColor; + + pdf = pdf.append(this.currentFill.getColorSpaceOut(true)); + //} + + int rx = this.currentXPosition; + int bl = this.currentYPosition; - Vector theExtend = new Vector(); - theExtend.addElement(new Boolean(true)); - theExtend.addElement(new Boolean(true)); + pdf = pdf.append("1 0 0 1 " + +(rx/1000f) + " " + (bl/1000f) + + " Tm ("); - Vector theDomain = new Vector(); - theDomain.addElement(new Double(0)); - theDomain.addElement(new Double(1)); + String s; + if ( area.getPageNumberID()!=null ) { // this text is a page number, so resolve it + s = idReferences.getPageNumber(area.getPageNumberID()); + if(s==null) + { + s=""; + } + } + else { + s = area.getText(); + } + + int l = s.length(); + + for (int i=0; i < l; i++) { + ch = s.charAt(i); + if (ch > 127) { + pdf = pdf.append("\\"); + pdf = pdf.append(Integer.toOctalString((int)ch)); + } else { + switch (ch) { + case '(' : pdf = pdf.append("\\("); break; + case ')' : pdf = pdf.append("\\)"); break; + case '\\' : pdf = pdf.append("\\\\"); break; + default : pdf = pdf.append(ch); break; + } + } + } + pdf = pdf.append(") Tj\n"); + + currentStream.add(pdf.toString()); + + this.currentXPosition += area.getContentWidth(); + } + + /** + * render inline space to PDF + * + * @param space space to render + */ + public void renderInlineSpace(InlineSpace space) { + this.currentXPosition += space.getSize(); + } + + /** + * render line area to PDF + * + * @param area area to render + */ + public void renderLineArea(LineArea area) { + int rx = this.currentAreaContainerXPosition + + area.getStartIndent(); + int ry = this.currentYPosition; + int w = area.getContentWidth(); + int h = area.getHeight(); + + this.currentYPosition -= area.getPlacementOffset(); + this.currentXPosition = rx; + + int bl = this.currentYPosition; + + Enumeration e = area.getChildren().elements(); + while (e.hasMoreElements()) { + Box b = (Box) e.nextElement(); + b.render(this); + } + + this.currentYPosition = ry-h; + } + + /** + * render page into PDF + * + * @param page page to render + */ + public void renderPage(Page page) { + AreaContainer body, before, after; + + currentStream = this.pdfDoc.makeStream(); + body = page.getBody(); + before = page.getBefore(); + after = page.getAfter(); + + this.currentFontName = ""; + this.currentFontSize = 0; + + currentStream.add("BT\n"); + renderAreaContainer(body); + + if (before != null) { + renderAreaContainer(before); + } + + if (after != null) { + renderAreaContainer(after); + } + + currentStream.add("ET\n"); + + currentPage = this.pdfDoc.makePage(this.pdfResources, currentStream, + page.getWidth()/1000, + page.getHeight()/1000, page); + + if (page.hasLinks()) { + currentAnnotList = this.pdfDoc.makeAnnotList(); + currentPage.setAnnotList(currentAnnotList); + + Enumeration e = page.getLinkSets().elements(); + while (e.hasMoreElements()) { + LinkSet linkSet = (LinkSet) e.nextElement(); + + linkSet.align(); + String dest = linkSet.getDest(); + int linkType = linkSet.getLinkType(); + Enumeration f = linkSet.getRects().elements(); + while (f.hasMoreElements()) { + LinkedRectangle lrect = (LinkedRectangle) f.nextElement(); + currentAnnotList.addLink( + this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType)); + } + } + } else { + // just to be on the safe side + currentAnnotList = null; + } + } + + /** + * render rule area into PDF + * + * @param area area to render + */ + public void renderRuleArea(RuleArea area) { + int rx = this.currentAreaContainerXPosition + + area.getStartIndent(); + int ry = this.currentYPosition; + int w = area.getContentWidth(); + int h = area.getHeight(); + int th = area.getRuleThickness(); + + addLine(rx, ry, rx+w, ry, th, new PDFColor(area.getRed(), area.getGreen(),area.getBlue())); + } + + /** + * set up the font info + * + * @param fontInfo font info to set up + */ + public void setupFontInfo(FontInfo fontInfo) { + FontSetup.setup(fontInfo); + FontSetup.addToResources(this.pdfDoc, fontInfo); + } + + // SVG Stuff + + public void renderGArea(FontState fontState, 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(fontState, (SVGElement)n, posx, posy); + } + } + } + + void handleSwitchElement(FontState fontState, int posx, int posy, SVGSwitchElement ael) + { + SVGList relist = ael.getRequiredExtensions(); + SVGList rflist = ael.getRequiredFeatures(); + SVGList sllist = ael.getSystemLanguage(); + org.w3c.dom.NodeList nl = ael.getChildNodes(); + 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; + SVGList grelist = graphic.getRequiredExtensions(); + // if null it evaluates to true + if(grelist != null) { + 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; +// } + } else { + } + } + } + SVGList grflist = graphic.getRequiredFeatures(); + if(grflist != null) { + 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; + } + } else { + boolean found = false; + for(int j = 0; j < rflist.getNumberOfItems(); j++) { + if(rflist.getItem(j).equals(str)) { + found = true; + break; + } + } + if(!found) + continue; + } + } + } + SVGList gsllist = graphic.getSystemLanguage(); + if(gsllist != null) { + 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; + } + } else { + boolean found = false; + for(int j = 0; j < sllist.getNumberOfItems(); j++) { + if(sllist.getItem(j).equals(str)) { + found = true; + break; + } + } + if(!found) + continue; + } + } + } + renderElement(fontState, (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; + str = "" + x1 + " " + y1 + " m " + + x2 + " " + y2 + " l"; + if(di != null && di.fill) + currentStream.add(str + " f\n"); // ?? + currentStream.add(str + " S\n"); + } + + protected void addCircle(float cx, float cy, float r, DrawingInstruction di) + { + String str; + str = "" + cx + " " + (cy - r) + " m\n" + + "" + (cx + 21 * r / 40f) + " " + (cy - r) + " " + (cx + r) + " " + (cy - 21 * r / 40f) + " " + (cx + r) + " " + cy + " c\n" + + "" + (cx + r) + " " + (cy + 21 * r / 40f) + " " + (cx + 21 * r / 40f) + " " + (cy + r) + " " + cx + " " + (cy + r) + " c\n" + + "" + (cx - 21 * r / 40f) + " " + (cy + r) + " " + (cx - r) + " " + (cy + 21 * r / 40f) + " " + (cx - r) + " " + cy + " c\n" + + "" + (cx - r) + " " + (cy - 21 * r / 40f) + " " + (cx - 21 * r / 40f) + " " + (cy - r) + " " + cx + " " + (cy - r) + " c\n"; + + currentStream.add(str); + doDrawing(di); + } + + protected void addEllipse(float cx, float cy, float rx, float ry, DrawingInstruction di) + { + String str; + str = "" + cx + " " + (cy - ry) + " m\n" + + "" + (cx + 21 * rx / 40f) + " " + (cy - ry) + " " + (cx + rx) + " " + (cy - 21 * ry / 40f) + " " + (cx + rx) + " " + cy + " c\n" + + "" + (cx + rx) + " " + (cy + 21 * ry / 40f) + " " + (cx + 21 * rx / 40f) + " " + (cy + ry) + " " + cx + " " + (cy + ry) + " c\n" + + "" + (cx - 21 * rx / 40f) + " " + (cy + ry) + " " + (cx - rx) + " " + (cy + 21 * ry / 40f) + " " + (cx - rx) + " " + cy + " c\n" + + "" + (cx - rx) + " " + (cy - 21 * ry / 40f) + " " + (cx - 21 * rx / 40f) + " " + (cy - ry) + " " + cx + " " + (cy - ry) + " c\n"; + currentStream.add(str); + doDrawing(di); + } + + /** + * add a filled rectangle to the current stream + * + * @param x the x position of left edge in millipoints + * @param y the y position of top edge in millipoints + * @param w the width in millipoints + * @param h the height in millipoints + * @param r the red component of edges + * @param g the green component of edges + * @param b the blue component of edges + * @param fr the red component of the fill + * @param fg the green component of the fill + * @param fb the blue component of the fill + */ + protected void addRect(float x, float y, float w, float h, float rx, float ry, DrawingInstruction di) + { + String str = ""; + if(rx == 0.0 && ry == 0.0) { + str = "" + x + " " + y + " " + w + " " + h + " re\n"; + } else { + str = "" + (x + rx) + " " + y + " m\n"; + str += "" + (x + w - rx) + " " + y + " l\n"; + str += "" + (x + w) + " " + y + " " + (x + w) + " " + y + " " + (x + w) + " " + (y + ry) + " c\n"; + str += "" + (x + w) + " " + (y + h - ry) + " l\n"; + str += "" + (x + w) + " " + (y + h) + " " + (x + w) + " " + (y + h) + " " + (x + w - rx) + " " + (y + h) + " c\n"; + str += "" + (x + rx) + " " + (y + h) + " l\n"; + str += "" + x + " " + (y + h) + " " + x + " " + (y + h) + " " + x + " " + (y + h - ry) + " c\n"; + str += "" + x + " " + (y + ry) + " l\n"; + str += "" + x + " " + y + " " + x + " " + y + " " + (x + rx) + " " + y + " c\n"; + } + currentStream.add(str); + doDrawing(di); + } + + protected void addPath(Vector points, int posx, int posy, DrawingInstruction di) + { + SVGPathSegImpl pathmoveto = null; + float lastx = 0; + float lasty = 0; + for(Enumeration e = points.elements(); e.hasMoreElements(); ) { + SVGPathSegImpl pc = (SVGPathSegImpl)e.nextElement(); + float[] vals = pc.getValues(); + float lastcx = 0; + float lastcy = 0; + switch(pc.getPathSegType()) { + case SVGPathSeg.PATHSEG_MOVETO_ABS: + pathmoveto = pc; + lastx = vals[0]; + lasty = vals[1]; + currentStream.add(lastx + " " + lasty + " m\n"); + break; + case SVGPathSeg.PATHSEG_MOVETO_REL: + if(pathmoveto == null) { + lastx = vals[0]; + lasty = vals[1]; + pathmoveto = pc; + currentStream.add(lastx + " " + lasty + " m\n"); + } else { + lastx += vals[0]; + lasty += vals[1]; + currentStream.add(lastx + " " + lasty + " l\n"); + } + break; + case SVGPathSeg.PATHSEG_LINETO_ABS: + lastx = vals[0]; + lasty = vals[1]; + currentStream.add(lastx + " " + lasty + " l\n"); + break; + case SVGPathSeg.PATHSEG_LINETO_REL: + lastx += vals[0]; + lasty += vals[1]; + currentStream.add(lastx + " " + lasty + " l\n"); + break; + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: + lasty = vals[0]; + currentStream.add(lastx + " " + lasty + " l\n"); + break; + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: + lasty += vals[0]; + currentStream.add(lastx + " " + lasty + " l\n"); + break; + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: + lastx = vals[0]; + currentStream.add(lastx + " " + lasty + " l\n"); + break; + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: + lastx += vals[0]; + currentStream.add(lastx + " " + lasty + " l\n"); + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: + lastx = vals[4]; + lasty = vals[5]; + lastcx = vals[2]; + lastcy = vals[3]; + currentStream.add((vals[0]) + " " + (vals[1]) + " " + + (vals[2]) + " " + (vals[3]) + " " + + lastx + " " + lasty + + " c\n"); + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: + currentStream.add((vals[0] + lastx) + " " + (vals[1] + lasty) + " " + + (vals[2] + lastx) + " " + (vals[3] + lasty) + " " + + (vals[4] + lastx) + " " + (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; + } + lastx = vals[2]; + lasty = vals[3]; + currentStream.add(lastcx + " " + lastcy + " " + + (vals[0]) + " " + (vals[1]) + " " + + lastx + " " + lasty + + " c\n"); + break; + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + if(lastcx == 0) { + lastcx = lastx; + } + if(lastcy == 0) { + lastcy = lasty; + } + currentStream.add(lastcx + " " + lastcy + " " + + (vals[0] + lastx) + " " + (vals[1] + lasty) + " " + + (vals[2] + lastx) + " " + (vals[3] + lasty) + + " c\n"); + lastx += vals[2]; + lasty += vals[3]; + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: + if(lastcx == 0) { + lastcx = lastx; + } + if(lastcy == 0) { + lastcy = lasty; + } + lastx = vals[0]; + lasty = vals[1]; + lastcx = 0; + lastcy = 0; + currentStream.add(lastcx + " " + lastcy + " " + + lastx + " " + lasty + + " y\n"); + break; + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: + if(lastcx == 0) { + lastcx = lastx; + } + if(lastcy == 0) { + lastcy = lasty; + } + currentStream.add(lastcx + " " + lastcy + " " + + (vals[0] + lastx) + " " + (vals[1] + lasty) + + " y\n"); + lastcx = 0; + lastcy = 0; + 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.add(contrx1 + " " + contry1 + " " + + contrx2 + " " + contry2 + " " + + vals[5] + " " + 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.add(contrx1 + " " + contry1 + " " + + contrx2 + " " + contry2 + " " + + (vals[5] + lastx) + " " + (vals[6] + lasty) + + " c\n"); + + lastcx = 0; //?? + lastcy = 0; //?? + lastx += vals[5]; + lasty += vals[6]; + } + break; + case SVGPathSeg.PATHSEG_CLOSEPATH: + currentStream.add("h\n"); + break; + } + } + doDrawing(di); + } + + protected void addPolyline(Vector points, int posx, int posy, DrawingInstruction di, boolean close) + { + 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.add(lastx + " " + lasty + " m\n"); + } + while(e.hasMoreElements()) { + pc = (PathPoint)e.nextElement(); + lastx = pc.x; + lasty = pc.y; + currentStream.add(lastx + " " + lasty + " l\n"); + } + if(close) + currentStream.add("h\n"); + doDrawing(di); + } + + protected void doDrawing(DrawingInstruction di) + { + if(di == null) { + currentStream.add("S\n"); + } else { + if(di.fill) { + if(di.stroke) { + if(!di.nonzero) + currentStream.add("B*\n"); + else + currentStream.add("B\n"); + } else { + if(!di.nonzero) + currentStream.add("f*\n"); + else + currentStream.add("f\n"); + } + } else { +// if(di.stroke) + currentStream.add("S\n"); + } + } + } + + public void renderImage(FontState fontState, String href, float x, float y, float width, float height) + { + try { + if(href.indexOf(":") == -1) { + href = "file:" + href; + } + FopImage img = FopImageFactory.Make(href); + if(img instanceof SVGImage) { + SVGSVGElement svg = ((SVGImage)img).getSVGDocument().getRootElement(); + currentStream.add("q\n" + width / svg.getWidth().getBaseVal().getValue() + " 0 0 " + height / svg.getHeight().getBaseVal().getValue() + " 0 0 cm\n"); + renderSVG(fontState, svg, (int)x * 1000, (int)y * 1000); + currentStream.add("Q\n"); +// renderSVG(svg); + } else if(img != null) { + int xObjectNum = this.pdfDoc.addImage(img); + currentStream.add("q\n1 0 0 -1 " + 0 + + " " + (2 * y + height) + " cm\n" + width + " 0 0 " + + height + " " + + x + " " + + y + " cm\n" + + "/Im" + xObjectNum + " Do\nQ\n"); +// img.close(); + } + } catch(Exception e) { +e.printStackTrace(); + System.err.println("could not add image to SVG: " + href); + } + } + + void renderSVG(FontState fontState, 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(fontState, (SVGElement)n, x, y); + } + } + } + + void handleGradient(String sp, 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); + address = address.trim(); + // local reference + if(address.startsWith("#")) { + // find the gradient element + SVGElement gi = null; +// gi = area.locateDef(address.substring(1, address.length())); +// System.out.println(gi + ":" + address.substring(1, address.length())); + if(gi instanceof SVGLinearGradientElement) { + SVGLinearGradientElement linear = (SVGLinearGradientElement)gi; + + Vector theCoords = new Vector(); + theCoords.addElement(new Double(linear.getX1().getBaseVal().getValue())); + theCoords.addElement(new Double(linear.getY1().getBaseVal().getValue())); + theCoords.addElement(new Double(linear.getX2().getBaseVal().getValue())); + theCoords.addElement(new Double(linear.getY2().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)); @@ -925,15 +1223,15 @@ public class PDFRenderer implements Renderer { Vector theFunctions = new Vector(); - org.w3c.dom.NodeList nl = linear.getChildNodes(); + NodeList nl = linear.getChildNodes(); Vector someColors = new Vector(); float lastoffset = 0; Vector lastVector = null; SVGStopElementImpl stop; - Hashtable table; + Hashtable table = null; for(int count = 0; count < nl.getLength(); count++) { stop = (SVGStopElementImpl)nl.item(count); - table = stop.oldgetStyle(); +// table = stop.oldgetStyle(); ColorType sc = (ColorType)table.get("stop-color"); if(sc == null) { // maybe using color @@ -977,7 +1275,7 @@ public class PDFRenderer implements Renderer { ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); org.w3c.dom.NodeList nl = radial.getChildNodes(); SVGStopElementImpl stop; - Hashtable table; + Hashtable table = null; Vector someColors = new Vector(); Vector theCoords = new Vector(); Vector theBounds = new Vector(); @@ -1038,7 +1336,7 @@ public class PDFRenderer implements Renderer { float lastoffset = 0; for(int count = 0; count < nl.getLength(); count++) { stop = (SVGStopElementImpl)nl.item(count); - table = stop.oldgetStyle(); +// table = stop.oldgetStyle(); ColorType sc = (ColorType)table.get("stop-color"); if(sc == null) { // maybe using color @@ -1079,14 +1377,28 @@ public class PDFRenderer implements Renderer { int linejoin = 0; // miter int miterwidth = 8; } - protected DrawingInstruction applyStyle(GraphicImpl area, Hashtable style) + protected DrawingInstruction applyStyle(SVGElement area, CSSStyleDeclaration style) { DrawingInstruction di = new DrawingInstruction(); - Object sp; - sp = style.get("fill"); + CSSValue sp; + sp = style.getPropertyCSSValue("fill"); if(sp != null) { - di.fill = true; - if(sp instanceof ColorType) { + 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.add(fillColour.getColorSpaceOut(true)); + di.fill = true; + } + } +/* if(sp instanceof ColorType) { ColorType ct = (ColorType)sp; PDFColor fillColour = new PDFColor(ct.red(), ct.green(), ct.blue()); currentStream.add(fillColour.getColorSpaceOut(true)); @@ -1096,713 +1408,653 @@ public class PDFRenderer implements Renderer { } else { handleGradient((String)sp, true, area); } - } + }*/ } else { } - sp = style.get("fill-rule"); + sp = style.getPropertyCSSValue("fill-rule"); if(sp != null) { - if(sp.equals("nonzero")) { - di.nonzero = true; - } + 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.get("stroke"); + sp = style.getPropertyCSSValue("stroke"); if(sp != null) { - di.stroke = true; - if(sp instanceof ColorType) { + 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.add(fillColour.getColorSpaceOut(false)); + di.stroke = true; + } + } +/* if(sp instanceof ColorType) { ColorType ct = (ColorType)sp; PDFColor fillColour = new PDFColor(ct.red(), ct.green(), ct.blue()); - currentStream.add(fillColour.getColorSpaceOut(false)); - } else if(sp instanceof String) { - if(sp.equals("none")) { - di.stroke = false; - } else { - handleGradient((String)sp, false, area); - } - } - } else { - } - sp = style.get("stroke-linecap"); - if(sp != null) { - // butt, round ,square - if(sp.equals("butt")) { - currentStream.add(0 + " J\n"); - } else if(sp.equals("round")) { - currentStream.add(1 + " J\n"); - } else if(sp.equals("square")) { - currentStream.add(2 + " J\n"); - } - } else { - } - sp = style.get("stroke-linejoin"); - if(sp != null) { - if(sp.equals("miter")) { - currentStream.add(0 + " j\n"); - } else if(sp.equals("round")) { - currentStream.add(1 + " j\n"); - } else if(sp.equals("bevel")) { - currentStream.add(2 + " j\n"); - } - } else { - } - sp = style.get("stroke-miterlimit"); - if(sp != null) { - float width; - width = ((SVGLengthImpl)sp).getValue(); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.add(pdfNumber.doubleOut(width) + " M\n"); - } else { - } - sp = style.get("stroke-width"); - if(sp != null) { - float width; - width = ((SVGLengthImpl)sp).getValue(); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.add(pdfNumber.doubleOut(width) + " w\n"); - } - sp = style.get("stroke-dasharray"); - if(sp != null) { - Vector list; - list = (Vector)sp; - currentStream.add("[ "); - for(Enumeration e = list.elements(); e.hasMoreElements(); ) { - Integer val = (Integer)e.nextElement(); - currentStream.add(val.intValue() + " "); - } - sp = style.get("stroke-offset"); - if(sp != null) { - float width; - width = ((SVGLengthImpl)sp).getValue(); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.add("] " + pdfNumber.doubleOut(width) + " d\n"); - } else { - currentStream.add("] 0 d\n"); - } - - } - sp = style.get("mask"); - if(sp != null) { - String maskurl; - maskurl = (String)sp; -// System.out.println("mask: " + maskurl); - maskurl = maskurl.substring(1, maskurl.length()); - // get def of mask and set mask - GraphicImpl graph = null; - graph = area.locateDef(maskurl); - if(graph != null) { -// System.out.println("mask: " + graph); - GraphicImpl parent = graph.getGraphicParent(); - graph.setParent(area); -// renderElement(svgarea, graph, posx, posy); - graph.setParent(parent); - } - } - return di; - } - - // need to transform about the origin of the current object - protected void applyTransform(Vector trans) - { - PDFNumber pdfNumber = new PDFNumber(); - for(Enumeration e = trans.elements(); e.hasMoreElements(); ) { - SVGTransform t = (SVGTransform)e.nextElement(); - SVGMatrix matrix = t.getMatrix(); - currentStream.add(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"); - } - } - - public void renderElement(SVGArea svgarea, GraphicImpl area, int posx, int posy) - { - int x = posx; - int y = posy; - Hashtable style = area.oldgetStyle(); - DrawingInstruction di = null; - - currentStream.add("q\n"); - Vector trans = area.oldgetTransform(); - if(trans != null) { - applyTransform(trans); - } - - if(style != null) { - di = applyStyle(area, style); - } - - 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.add("BT\n"); - renderText(svgarea, (SVGTextElementImpl)area, 0, 0/*, di*/); - currentStream.add("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, posx, posy, di, false); - } else if (area instanceof SVGPolygonElementImpl) { - addPolyline(((SVGPolygonElementImpl)area).points, posx, posy, di, true); - } else if (area instanceof SVGGElementImpl) { - renderGArea(svgarea, (SVGGElementImpl)area, x, y); - } else if(area instanceof SVGUseElementImpl) { - SVGUseElementImpl ug = (SVGUseElementImpl)area; - String ref = ug.link; - ref = ref.substring(1, ref.length()); - GraphicImpl graph = null; - graph = area.locateDef(ref); - if(graph != null) { - // probably not the best way to do this, should be able - // to render without the style being set. - GraphicImpl parent = graph.getGraphicParent(); - graph.setParent(area); - // need to clip (if necessary) to the use area - // the style of the linked element is as if is was - // a direct descendant of the use element. - renderElement(svgarea, graph, posx, posy); - graph.setParent(parent); - } - } else if (area instanceof SVGImageElementImpl) { - SVGImageElementImpl ig = (SVGImageElementImpl)area; - renderImage(ig.link, ig.x, ig.y, ig.width, ig.height); - } else if (area instanceof SVGArea) { - // the x and y pos will be wrong! - Enumeration e = ((SVGArea)area).getChildren().elements(); - currentStream.add("q\n"); - while (e.hasMoreElements()) { - Object o = e.nextElement(); - if(o instanceof GraphicImpl) { - renderElement((SVGArea)area, (GraphicImpl)o, x, y); - } - } - currentStream.add("Q\n"); - } 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 GraphicImpl) { - 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(svgarea, (GraphicImpl)n, posx, posy); - } - } - } else if (area instanceof SVGSwitchElement) { - handleSwitchElement(svgarea, posx, posy, (SVGSwitchElement)area); - } - // should be done with some cleanup code, so only - // required values are reset. - currentStream.add("Q\n"); - } - -// need to escape certain chars - public void renderText(SVGArea svgarea, SVGTextElementImpl tg, float x, float y) - { - FontState fontState = svgarea.getFontState(); - if(fontState == null) { - return; // for now - } - PDFNumber pdfNumber = new PDFNumber(); - - Hashtable styles; - styles = tg.oldgetStyle(); - applyStyle(tg, styles); - // apply transform - // text has a Tm and need to handle each element - SVGTransformList trans = tg.getTransform().getBaseVal(); - SVGMatrix matrix = trans.consolidate().getMatrix(); - String transstr = (pdfNumber.doubleOut(matrix.getA()) - + " " + pdfNumber.doubleOut(matrix.getB()) - + " " + pdfNumber.doubleOut(matrix.getC()) - + " " + pdfNumber.doubleOut(-matrix.getD()) + " "); - - String fontFamily; - fontFamily = (String)styles.get("font-family"); - if(fontFamily == null) - fontFamily = fontState.getFontFamily(); - String fontStyle; - fontStyle = (String)styles.get("font-style"); - if(fontStyle == null) - fontStyle = fontState.getFontStyle(); - String fontWeight; - fontWeight = (String)styles.get("font-weight"); - if(fontWeight == null) - fontWeight = fontState.getFontWeight(); - SVGLength len; - len = (SVGLength)styles.get("font-size"); - float fontSize; - fontSize = fontState.getFontSize() / 1000f; - if(len != null) - fontSize = len.getValue(); - FontState fs = fontState; - try { - fs = new FontState(fontState.getFontInfo(), fontFamily, fontStyle, - fontWeight, (int)(fontSize * 1000)); - } catch(Exception fope) { -// fope.printStackTrace(); - } - - currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n"); - - float tx = tg.x; - float ty = tg.y; - float currentX = x + tx; - Vector list = tg.textList; - for(Enumeration e = list.elements(); e.hasMoreElements(); ) { - Object o = e.nextElement(); - if(o instanceof String) { - String str = (String)o; - currentStream.add(transstr - + (currentX + matrix.getE()) + " " - + (y+ty + matrix.getF()) + " Tm " - + "(" + str + ") Tj\n"); - for(int count = 0; count < str.length(); count++) { - currentX += fs.width(str.charAt(count)) / 1000f; - } - currentX += fs.width(' ') / 1000f; - } else if(o instanceof SVGTextPathElementImpl) { - SVGTextPathElementImpl tpg = (SVGTextPathElementImpl)o; - String ref = tpg.str; - GraphicImpl graph = null; - graph = tpg.locateDef(ref); - if(graph != null && 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; - ref = ref.substring(1, ref.length()); - GraphicImpl graph = null; - graph = trg.locateDef(ref); - if(graph != null && graph instanceof SVGTextElementImpl) { - GraphicImpl parent = graph.getGraphicParent(); - graph.setParent(trg); - SVGTextElementImpl te = (SVGTextElementImpl)graph; - renderText(svgarea, te, (int)(x + tx), (int)(y + ty)); - graph.setParent(parent); - } - } else if(o instanceof SVGTSpanElementImpl) { - // TODO handle dy properly - SVGTSpanElementImpl tsg = (SVGTSpanElementImpl)o; - styles = tsg.oldgetStyle(); - applyStyle(tsg, styles); - boolean changed = false; - - String newprop; - newprop = (String)styles.get("font-family"); - if(newprop != null && !newprop.equals(fontFamily)) { - fontFamily = newprop; - changed = true; - } - newprop = (String)styles.get("font-style"); - if(newprop != null && !newprop.equals(fontStyle)) { - fontStyle = newprop; - changed = true; - } - newprop = (String)styles.get("font-weight"); - if(newprop != null && !newprop.equals(fontWeight)) { - fontWeight = newprop; - changed = true; - } - len = (SVGLengthImpl)styles.get("font-size"); - if(len != null) { - float newSize = len.getValue(); - if(fontSize != newSize) { - fontSize = newSize; - changed = true; - } - } - if(changed) { - try { - fs = new FontState(fontState.getFontInfo(), fontFamily, fontStyle, - fontWeight, (int)(fontSize * 1000)); - } catch(Exception fope) { - } - - currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n"); - } - - if(tsg.ylist != null) { - ty = ((Float)tsg.ylist.elementAt(0)).floatValue(); + currentStream.add(fillColour.getColorSpaceOut(false)); + } else if(sp instanceof String) { + if(sp.equals("none")) { + di.stroke = false; + } else { + handleGradient((String)sp, false, area); } - if(tsg.xlist != null) { - Enumeration enum = tsg.xlist.elements(); - int count = 0; - while(enum.hasMoreElements() && count < tsg.str.length()) { - float pos = ((Float)enum.nextElement()).floatValue(); - currentStream.add(transstr - + (x + pos + matrix.getE()) + " " - + (y + ty + tsg.dy + matrix.getF()) + " Tm " - + "(" + tsg.str.charAt(count) + ") Tj\n"); - currentX = x + pos + fs.width(tsg.str.charAt(count)) / 1000f; - count++; - } - if(enum.hasMoreElements()) { - // do nothing - } else if(count < tsg.str.length()) { - currentStream.add(transstr - + (currentX + matrix.getE()) + " " - + (y + ty + tsg.dy + matrix.getF()) + " Tm " - + "(" + tsg.str.substring(count, tsg.str.length()) + ") Tj\n"); - } - } else if(tsg.dxlist != null) { - Enumeration enum = tsg.dxlist.elements(); - int count = 0; - while(enum.hasMoreElements() && count < tsg.str.length()) { - float pos = ((Float)enum.nextElement()).floatValue(); - currentStream.add(transstr - + (currentX + pos + matrix.getE()) + " " - + (y + ty + tsg.dy + matrix.getF()) + " Tm " - + "(" + tsg.str.charAt(count) + ") Tj\n"); - currentX += pos + fs.width(tsg.str.charAt(count)) / 1000f; - count++; + }*/ + } else { + } + sp = style.getPropertyCSSValue("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.add(0 + " J\n"); + } else if(str.equals("round")) { + currentStream.add(1 + " J\n"); + } else if(str.equals("square")) { + currentStream.add(2 + " J\n"); } - if(enum.hasMoreElements()) { - // do nothing - } else if(count < tsg.str.length()) { - currentStream.add(transstr - + (currentX + matrix.getE()) + " " - + (y + ty + tsg.dy + matrix.getF()) + " Tm " - + "(" + tsg.str.substring(count, tsg.str.length()) + ") Tj\n"); + } + } + } else { + } + sp = style.getPropertyCSSValue("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.add(0 + " j\n"); + } else if(str.equals("round")) { + currentStream.add(1 + " j\n"); + } else if(str.equals("bevel")) { + currentStream.add(2 + " j\n"); } + } + } + } else { + } + sp = style.getPropertyCSSValue("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.add(pdfNumber.doubleOut(width) + " M\n"); + } + } else { + } + sp = style.getPropertyCSSValue("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.add(pdfNumber.doubleOut(width) + " w\n"); + } + } + sp = style.getPropertyCSSValue("stroke-dasharray"); + if(sp != null) { + if(sp.getValueType() == CSSValue.CSS_VALUE_LIST) { + currentStream.add("[ "); + 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.add(((CSSPrimitiveValue)val).getFloatValue(CSSPrimitiveValue.CSS_NUMBER) + " "); + } + } + currentStream.add("] "); + sp = style.getPropertyCSSValue("stroke-offset"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + currentStream.add(((CSSPrimitiveValue)sp).getFloatValue(CSSPrimitiveValue.CSS_NUMBER) + " d\n"); } else { -/* currentStream.add(transstr - + (((tsg.x == 0) ? (currentX) : (x))/1000f + tsg.x) + " " - + (y / 1000f - ((tsg.y == 0) ? (ty + tsg.dy) : tsg.y)) + " Tm " - + "(" + tsg.str + ") Tj\n"); - currentX = (tsg.x == 0) ? (currentX + tsg.dx) : (x + tsg.x); - for(int count = 0; count < tsg.str.length(); count++) { - currentX += fs.width(tsg.str.charAt(count)); - }*/ + currentStream.add("0 d\n"); } - currentX += fs.width(' ') / 1000f; - } else { - System.err.println("Error: unknown text element " + o); + } +/* Vector list; + list = (Vector)sp; + currentStream.add("[ "); + for(Enumeration e = list.elements(); e.hasMoreElements(); ) { + Integer val = (Integer)e.nextElement(); + currentStream.add(val.intValue() + " "); } + sp = style.getPropertyCSSValue("stroke-offset"); + if(sp != null) { + float width; + width = ((SVGLengthImpl)sp).getValue(); + PDFNumber pdfNumber = new PDFNumber(); + currentStream.add("] " + pdfNumber.doubleOut(width) + " d\n"); + } else { + currentStream.add("] 0 d\n"); + }*/ + + } + sp = style.getPropertyCSSValue("mask"); + if(sp != null) { + String maskurl; +// maskurl = (String)sp; +// System.out.println("mask: " + maskurl); +// maskurl = maskurl.substring(1, maskurl.length()); + // get def of mask and set mask +// SVGElement graph = null; +// graph = area.locateDef(maskurl); +// if(graph != null) { +// System.out.println("mask: " + graph); +// SVGElement parent = graph.getGraphicParent(); +// graph.setParent(area); +// renderElement(svgarea, graph, posx, posy); +// graph.setParent(parent); +// } } + return di; } - public void renderGArea(SVGArea svgarea, SVGGElementImpl area, int posx, int posy) + // need to transform about the origin of the current object + protected void applyTransform(SVGAnimatedTransformList trans, SVGRect bbox) { - Enumeration e = area.getChildren().elements(); - while (e.hasMoreElements()) { - Object o = e.nextElement(); - if(o instanceof GraphicImpl) { - renderElement(svgarea, (GraphicImpl)o, posx, posy); - } + // need to rotate and scale about the bbox top left + PDFNumber pdfNumber = new PDFNumber(); + if(bbox != null) { +// currentStream.add("1 0 0 1 " + pdfNumber.doubleOut(bbox.getX()) + " " + pdfNumber.doubleOut(bbox.getY()) + " cm\n"); + } + SVGTransformList list = trans.getBaseVal(); + for(int count = 0; count < list.getNumberOfItems(); count++) { + SVGMatrix matrix = ((SVGTransform)list.getItem(count)).getMatrix(); + currentStream.add(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"); + } + if(bbox != null) { +// currentStream.add("1 0 0 1 " + pdfNumber.doubleOut(-bbox.getX()) + " " + pdfNumber.doubleOut(-bbox.getY()) + " cm\n"); } } - void handleSwitchElement(SVGArea svgarea, int posx, int posy, SVGSwitchElement ael) + public void renderElement(FontState fontState, SVGElement area, int posx, int posy) { - SVGList relist = ael.getRequiredExtensions(); - SVGList rflist = ael.getRequiredFeatures(); - SVGList sllist = ael.getSystemLanguage(); - org.w3c.dom.NodeList nl = ael.getChildNodes(); - 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; - SVGList grelist = graphic.getRequiredExtensions(); - // if null it evaluates to true - if(grelist != null) { - 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; -// } - } else { - } - } - } - SVGList grflist = graphic.getRequiredFeatures(); - if(grflist != null) { - 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; - } - } else { - boolean found = false; - for(int j = 0; j < rflist.getNumberOfItems(); j++) { - if(rflist.getItem(j).equals(str)) { - found = true; - break; - } - } - if(!found) - continue; - } - } - } - SVGList gsllist = graphic.getSystemLanguage(); - if(gsllist != null) { - 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; - } - } else { - boolean found = false; - for(int j = 0; j < sllist.getNumberOfItems(); j++) { - if(sllist.getItem(j).equals(str)) { - found = true; - break; - } - } - if(!found) - continue; - } - } - } - renderElement(svgarea, (GraphicImpl)n, posx, posy); - // only render the first valid one - break; + int x = posx; + int y = posy; + CSSStyleDeclaration style = null; + if(area instanceof SVGStylable) + style = ((SVGStylable)area).getStyle(); + DrawingInstruction di = null; + + currentStream.add("q\n"); + if(area instanceof SVGTransformable) { + SVGTransformable tf = (SVGTransformable)area; + SVGAnimatedTransformList trans = tf.getTransform(); + SVGRect bbox = tf.getBBox(); + if(trans != null) { + applyTransform(trans, bbox); } } - } - - /** - * render inline area to PDF - * - * @param area inline area to render - */ - public void renderInlineArea(InlineArea area) { - char ch; - StringBuffer pdf = new StringBuffer(); - - String name = area.getFontState().getFontName(); - int size = area.getFontState().getFontSize(); - - PDFColor theAreaColor = new PDFColor( - (double)area.getRed(), - (double)area.getGreen(), - (double)area.getBlue() ); - - if ((!name.equals(this.currentFontName)) - || (size != this.currentFontSize)) { - this.currentFontName = name; - this.currentFontSize = size; - pdf = pdf.append("/" + name + " " + (size/1000) + " Tf\n"); - } - - //if (theAreaColor.isEquivalent(this.currentFill)) { - this.currentFill = theAreaColor; - - pdf = pdf.append(this.currentFill.getColorSpaceOut(true)); - //} - - int rx = this.currentXPosition; - int bl = this.currentYPosition; - - pdf = pdf.append("1 0 0 1 " - +(rx/1000f) + " " + (bl/1000f) - + " Tm ("); - - String s; - if ( area.getPageNumberID()!=null ) { // this text is a page number, so resolve it - s = idReferences.getPageNumber(area.getPageNumberID()); - if(s==null) - { - s=""; - } - } - else { - s = area.getText(); - } - - int l = s.length(); - for (int i=0; i < l; i++) { - ch = s.charAt(i); - if (ch > 127) { - pdf = pdf.append("\\"); - pdf = pdf.append(Integer.toOctalString((int)ch)); - } else { - switch (ch) { - case '(' : pdf = pdf.append("\\("); break; - case ')' : pdf = pdf.append("\\)"); break; - case '\\' : pdf = pdf.append("\\\\"); break; - default : pdf = pdf.append(ch); break; + if(style != null) { + di = applyStyle(area, style); } + + 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.add("BT\n"); + renderText(fontState, (SVGTextElementImpl)area, 0, 0/*, di*/); + currentStream.add("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, posx, posy, di, false); + } else if (area instanceof SVGPolygonElementImpl) { + addPolyline(((SVGPolygonElementImpl)area).points, posx, posy, di, true); + } else if (area instanceof SVGGElementImpl) { + renderGArea(fontState, (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 = area.locateDef(ref); + 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 is was + // a direct descendant of the use element. + renderElement(fontState, graph, posx, posy); +// graph.setParent(parent); + } + } else if (area instanceof SVGImageElementImpl) { + SVGImageElementImpl ig = (SVGImageElementImpl)area; + renderImage(fontState, ig.link, ig.x, ig.y, ig.width, ig.height); + } else if (area instanceof SVGSVGElement) { + // the x and y pos will be wrong! + currentStream.add("q\n"); + renderSVG(fontState, (SVGSVGElement)area, x, y); + currentStream.add("Q\n"); + } 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(fontState, (SVGElement)n, posx, posy); + } + } + } else if (area instanceof SVGSwitchElement) { + handleSwitchElement(fontState, posx, posy, (SVGSwitchElement)area); } + // should be done with some cleanup code, so only + // required values are reset. + currentStream.add("Q\n"); } - pdf = pdf.append(") Tj\n"); - - currentStream.add(pdf.toString()); - - this.currentXPosition += area.getContentWidth(); - } - - /** - * render inline space to PDF - * - * @param space space to render - */ - public void renderInlineSpace(InlineSpace space) { - this.currentXPosition += space.getSize(); - } - - /** - * render line area to PDF - * - * @param area area to render - */ - public void renderLineArea(LineArea area) { - int rx = this.currentAreaContainerXPosition - + area.getStartIndent(); - int ry = this.currentYPosition; - int w = area.getContentWidth(); - int h = area.getHeight(); - - this.currentYPosition -= area.getPlacementOffset(); - this.currentXPosition = rx; - - int bl = this.currentYPosition; - - Enumeration e = area.getChildren().elements(); - while (e.hasMoreElements()) { - Box b = (Box) e.nextElement(); - b.render(this); - } - - this.currentYPosition = ry-h; - } - - /** - * render page into PDF - * - * @param page page to render - */ - public void renderPage(Page page) { - AreaContainer body, before, after; - - currentStream = this.pdfDoc.makeStream(); - body = page.getBody(); - before = page.getBefore(); - after = page.getAfter(); - this.currentFontName = ""; - this.currentFontSize = 0; + public void renderText(FontState fontState, SVGTextElementImpl tg, float x, float y) + { + PDFNumber pdfNumber = new PDFNumber(); - currentStream.add("BT\n"); - renderAreaContainer(body); + CSSStyleDeclaration styles; + styles = tg.getStyle(); + applyStyle(tg, styles); + // apply transform + // text has a Tm and need to handle each element + SVGTransformList trans = tg.getTransform().getBaseVal(); + SVGMatrix matrix = trans.consolidate().getMatrix(); + String transstr = (pdfNumber.doubleOut(matrix.getA()) + + " " + pdfNumber.doubleOut(matrix.getB()) + + " " + pdfNumber.doubleOut(matrix.getC()) + + " " + pdfNumber.doubleOut(-matrix.getD()) + " "); - if (before != null) { - renderAreaContainer(before); - } + String fontFamily = null; + CSSValue sp = styles.getPropertyCSSValue("font-family"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) { + fontFamily = sp.getCssText(); + } + } + if(fontFamily == null) + fontFamily = fontState.getFontFamily(); + String fontStyle = null; + sp = styles.getPropertyCSSValue("font-style"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) { + fontStyle = sp.getCssText(); + } + } + if(fontStyle == null) + fontStyle = fontState.getFontStyle(); + String fontWeight = null; + sp = styles.getPropertyCSSValue("font-weight"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) { + fontWeight = sp.getCssText(); + } + } + if(fontWeight == null) + fontWeight = fontState.getFontWeight(); + float fontSize; + sp = styles.getPropertyCSSValue("font-size"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { +// if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_NUMBER) { + fontSize = ((CSSPrimitiveValue)sp).getFloatValue(CSSPrimitiveValue.CSS_PT); +// } + } else { + fontSize = fontState.getFontSize() / 1000f; + } + FontState fs = fontState; + try { + fs = new FontState(fontState.getFontInfo(), fontFamily, fontStyle, + fontWeight, (int)(fontSize * 1000)); + } catch(Exception fope) { +// fope.printStackTrace(); + } - if (after != null) { - renderAreaContainer(after); - } - - currentStream.add("ET\n"); + currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n"); - currentPage = this.pdfDoc.makePage(this.pdfResources, currentStream, - page.getWidth()/1000, - page.getHeight()/1000, page); + float tx = tg.x; + float ty = tg.y; + float currentX = x + tx; + float currentY = y + ty; + Vector list = tg.textList; + for(Enumeration e = list.elements(); e.hasMoreElements(); ) { + Object o = e.nextElement(); + styles = tg.getStyle(); + applyStyle(tg, styles); + if(o instanceof String) { + String str = (String)o; + currentStream.add(transstr + + (currentX + matrix.getE()) + " " + + (y+ty + matrix.getF()) + " Tm " + + "("); + boolean spacing = "preserve".equals(tg.getXMLspace()); + currentX = addSVGStr(fs, currentX, str, spacing); + currentStream.add(") Tj\n"); +// for(int count = 0; count < str.length(); count++) { +// } +// currentX += fs.width(' ') / 1000f; + } else if(o instanceof SVGTextPathElementImpl) { + SVGTextPathElementImpl tpg = (SVGTextPathElementImpl)o; + String ref = tpg.str; + SVGElement graph = null; +// graph = tpg.locateDef(ref); + if(graph != null && 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; + ref = ref.substring(1, ref.length()); + SVGElement graph = null; +// graph = trg.locateDef(ref); + if(graph != null && graph instanceof SVGTextElementImpl) { +// GraphicImpl parent = graph.getGraphicParent(); +// graph.setParent(trg); + SVGTextElementImpl te = (SVGTextElementImpl)graph; + renderText(fs, te, (int)(x + tx), (int)(y + ty)); +// graph.setParent(parent); + } + } else if(o instanceof SVGTSpanElementImpl) { + SVGTSpanElementImpl tsg = (SVGTSpanElementImpl)o; + styles = tsg.getStyle(); + applyStyle(tsg, styles); + boolean changed = false; - if (page.hasLinks()) { - currentAnnotList = this.pdfDoc.makeAnnotList(); - currentPage.setAnnotList(currentAnnotList); + String newprop = null; + sp = styles.getPropertyCSSValue("font-family"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) { + newprop = sp.getCssText(); + } + } + if(newprop != null && !newprop.equals(fontFamily)) { + fontFamily = newprop; + changed = true; + } + sp = styles.getPropertyCSSValue("font-style"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) { + newprop = sp.getCssText(); + } + } + if(newprop != null && !newprop.equals(fontStyle)) { + fontStyle = newprop; + changed = true; + } + sp = styles.getPropertyCSSValue("font-weight"); + if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { + if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) { + newprop = sp.getCssText(); + } + } + if(newprop != null && !newprop.equals(fontWeight)) { + fontWeight = newprop; + changed = true; + } + float newSize = fontSize; + sp = styles.getPropertyCSSValue("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(fontSize != newSize) { + fontSize = newSize; + changed = true; + } + FontState oldfs = null; + if(changed) { + oldfs = fs; + try { + fs = new FontState(fontState.getFontInfo(), fontFamily, fontStyle, + fontWeight, (int)(fontSize * 1000)); + } catch(Exception fope) { + } - Enumeration e = page.getLinkSets().elements(); - while (e.hasMoreElements()) { - LinkSet linkSet = (LinkSet) e.nextElement(); + currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n"); + } - linkSet.align(); - String dest = linkSet.getDest(); - int linkType = linkSet.getLinkType(); - Enumeration f = linkSet.getRects().elements(); - while (f.hasMoreElements()) { - LinkedRectangle lrect = (LinkedRectangle) f.nextElement(); - currentAnnotList.addLink( - this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType)); - } + float baseX; + float baseY; + + StringBuffer pdf = new StringBuffer(); + boolean spacing = "preserve".equals(tsg.getXMLspace()); + boolean inbetween = false; + boolean addedspace = false; + int charPos = 0; + float xpos = currentX; + float ypos = currentY; + for (int i=0; i < tsg.str.length(); i++) { + char ch = tsg.str.charAt(i); + xpos = currentX; + ypos = currentY; + if(tsg.ylist.size() > charPos) { + ypos = y + ty + ((Float)tsg.ylist.elementAt(charPos)).floatValue(); + } + if(tsg.dylist.size() > charPos) { + ypos = ypos + ((Float)tsg.dylist.elementAt(charPos)).floatValue(); + } + if(tsg.xlist.size() > charPos) { + xpos = x + tx + ((Float)tsg.xlist.elementAt(charPos)).floatValue(); + } + if(tsg.dxlist.size() > charPos) { + xpos = xpos + ((Float)tsg.dxlist.elementAt(charPos)).floatValue(); + } + 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 ' ': + 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.add(pdf.toString()); + } +// currentX += fs.width(' ') / 1000f; + if(changed) { + fs = oldfs; + currentStream.add("/" + fs.getFontName() + " " + fs.getFontSize() / 1000f + " Tf\n"); + } + } else { + System.err.println("Error: unknown text element " + o); + } } - } else { - // just to be on the safe side - currentAnnotList = null; - } } - /** - * render rule area into PDF - * - * @param area area to render - */ - public void renderRuleArea(RuleArea area) { - int rx = this.currentAreaContainerXPosition - + area.getStartIndent(); - int ry = this.currentYPosition; - int w = area.getContentWidth(); - int h = area.getHeight(); - int th = area.getRuleThickness(); - - addLine(rx, ry, rx+w, ry, th, new PDFColor(area.getRed(), area.getGreen(),area.getBlue())); + 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 ' ': + 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.add(pdf.toString()); + return currentX; } - /** - * set up the font info - * - * @param fontInfo font info to set up - */ - public void setupFontInfo(FontInfo fontInfo) { - FontSetup.setup(fontInfo); - FontSetup.addToResources(this.pdfDoc, fontInfo); - } } -- 2.39.5