diff options
Diffstat (limited to 'src/org/apache/fop/render/pdf')
-rw-r--r-- | src/org/apache/fop/render/pdf/PDFRenderer.java | 1718 |
1 files changed, 985 insertions, 733 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,6 +201,556 @@ public class PDFRenderer implements Renderer { + "Q\nBT\n"); } + /** + * add a 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 stroke the stroke color/gradient + */ + protected void addRect(int x, int y, int w, int h, + PDFPathPaint stroke) { + currentStream.add("ET\nq\n" + + stroke.getColorSpaceOut(false) + + (x/1000f) + " " + (y/1000f) + " " + + (w/1000f) + " " + (h/1000f) + " re s\n" + + "Q\nBT\n"); + } + + /** + * 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 fill the fill color/gradient + * @param stroke the stroke color/gradient + */ + protected void addRect(int x, int y, int w, int h, + PDFPathPaint stroke, + PDFPathPaint fill) { + currentStream.add("ET\nq\n" + + fill.getColorSpaceOut(true) + + stroke.getColorSpaceOut(false) + + (x/1000f) + " " + (y/1000f) + " " + + (w/1000f) + " " + (h/1000f) + " re b\n" + + "Q\nBT\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; + } + + doFrame(area); + + Enumeration e = area.getChildren().elements(); + while (e.hasMoreElements()) { + Box b = (Box) e.nextElement(); + b.render(this); + } + if (area.getPosition() != Position.STATIC) { + this.currentYPosition = saveY; + this.currentAreaContainerXPosition = saveX; + } else + this.currentYPosition -= area.getHeight(); + } + + private void doFrame(Area area) { + int w, h; + int rx = this.currentAreaContainerXPosition; + w = area.getContentWidth(); + if (area instanceof BlockArea) + rx += ((BlockArea)area).getStartIndent(); + h = area.getContentHeight(); + int ry = this.currentYPosition; + ColorType bg = area.getBackgroundColor(); + + rx = rx - area.getPaddingLeft(); + ry = ry + area.getPaddingTop(); + w = w + area.getPaddingLeft() + area.getPaddingRight(); + h = h + area.getPaddingTop() + area.getPaddingBottom(); + + // I'm not sure I should have to check for bg being null + // but I do + if ((bg != null) && (bg.alpha() == 0)) { + this.addRect(rx, ry, w, -h, + new PDFColor(bg), + new PDFColor(bg)); + } + + rx = rx - area.borderWidthLeft; + ry = ry + area.borderWidthTop; + w = w + area.borderWidthLeft + area.borderWidthRight; + h = h + area.borderWidthTop + area.borderWidthBottom; + + if (area.borderWidthTop != 0) + addLine(rx, ry, rx + w, ry, + area.borderWidthTop, + new PDFColor(area.borderColorTop)); + if (area.borderWidthLeft != 0) + addLine(rx, ry, rx, ry - h, + area.borderWidthLeft, + new PDFColor(area.borderColorLeft)); + if (area.borderWidthRight != 0) + addLine(rx + w, ry, rx + w, ry - h, + area.borderWidthRight, + new PDFColor(area.borderColorRight)); + if (area.borderWidthBottom != 0) + addLine(rx, ry - h, rx + w, ry - h, + area.borderWidthBottom, + new PDFColor(area.borderColorBottom)); + + } + + + /** + * render block area to PDF + * + * @param area the block area to render + */ + public void renderBlockArea(BlockArea area) { + doFrame(area); + Enumeration e = area.getChildren().elements(); + while (e.hasMoreElements()) { + Box b = (Box) e.nextElement(); + b.render(this); + } + } + + /** + * render display space to PDF + * + * @param space the display space to render + */ + public void renderDisplaySpace(DisplaySpace space) { + int d = space.getSize(); + this.currentYPosition -= d; + } + + /** + * render image area to PDF + * + * @param area the image area to render + */ + public void renderImageArea(ImageArea area) { + // adapted from contribution by BoBoGi + int x = this.currentAreaContainerXPosition + + area.getXOffset(); + int y = this.currentYPosition; + int w = area.getContentWidth(); + int h = area.getHeight(); + + this.currentYPosition -= h; + + FopImage img = area.getImage(); + + int xObjectNum = this.pdfDoc.addImage(img); + + currentStream.add("ET\nq\n" + (((float) w) / 1000f) + " 0 0 " + + (((float) h) / 1000f) + " " + + (((float) x) / 1000f) + " " + + (((float) (y - h)) / 1000f) + " cm\n" + + "/Im" + xObjectNum + " Do\nQ\nBT\n"); + } + + /** render a foreign object area */ + public void renderForeignObjectArea(ForeignObjectArea area) + { + // if necessary need to scale and align the content + int x = this.currentAreaContainerXPosition; + switch(area.getAlign()) { + case TextAlign.START: + break; + case TextAlign.END: + break; + case TextAlign.CENTER: + case TextAlign.JUSTIFY: + break; + } + switch(area.getVerticalAlign()) { + case VerticalAlign.BASELINE: + break; + case VerticalAlign.MIDDLE: + break; + case VerticalAlign.SUB: + break; + case VerticalAlign.SUPER: + break; + case VerticalAlign.TEXT_TOP: + break; + case VerticalAlign.TEXT_BOTTOM: + break; + case VerticalAlign.TOP: + break; + case VerticalAlign.BOTTOM: + break; + } + // in general the content will not be text + currentStream.add("ET\n"); + // align and scale + currentStream.add("q\n"); + switch(area.scalingMethod()) { + case Scaling.UNIFORM: + break; + case Scaling.NON_UNIFORM: + break; + } + // if the overflow is auto (default), scroll or visible + // then the contents should not be clipped, since this + // is considered a printing medium. + switch(area.getOverflow()) { + case Overflow.VISIBLE: + case Overflow.SCROLL: + case Overflow.AUTO: + break; + case Overflow.HIDDEN: + break; + } + area.getObject().render(this); + currentStream.add("Q\n"); + currentStream.add("BT\n"); + this.currentYPosition -= area.getEffectiveHeight(); + } + + /** + * render SVG area to PDF + * + * @param area the SVG area to render + */ + public void renderSVGArea(SVGArea area) { + int x = this.currentAreaContainerXPosition; + int y = this.currentYPosition; + 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. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ + currentStream.add("q\n"); + currentStream.add(x / 1000f + " " + y / 1000f + " m\n"); + currentStream.add((x + w) / 1000f + " " + y / 1000f + " l\n"); + currentStream.add((x + w) / 1000f + " " + (y - h) / 1000f + " l\n"); + currentStream.add(x / 1000f + " " + (y - h) / 1000f + " l\n"); + currentStream.add("h\n"); + currentStream.add("W\n"); + currentStream.add("n\n"); + // transform so that the coordinates (0,0) is from the top left + // and positive is down and to the right + currentStream.add(1 + " " + 0 + " " + 0 + " " + (-1) + " " + x / 1000f + " " + y / 1000f + " cm\n"); + + // TODO - translate and clip to viewbox + + renderSVG(area.getFontState(), svg, x, y); + + currentStream.add("Q\n"); + } + + /** + * 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; + } + } + } + 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 * @@ -280,45 +832,6 @@ public class PDFRenderer implements Renderer { doDrawing(di); } - /** - * add a 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 stroke the stroke color/gradient - */ - protected void addRect(int x, int y, int w, int h, - PDFPathPaint stroke) { - currentStream.add("ET\nq\n" - + stroke.getColorSpaceOut(false) - + (x/1000f) + " " + (y/1000f) + " " - + (w/1000f) + " " + (h/1000f) + " re s\n" - + "Q\nBT\n"); - } - - /** - * 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 fill the fill color/gradient - * @param stroke the stroke color/gradient - */ - protected void addRect(int x, int y, int w, int h, - PDFPathPaint stroke, - PDFPathPaint fill) { - currentStream.add("ET\nq\n" - + fill.getColorSpaceOut(true) - + stroke.getColorSpaceOut(false) - + (x/1000f) + " " + (y/1000f) + " " - + (w/1000f) + " " + (h/1000f) + " re b\n" - + "Q\nBT\n"); - } - protected void addPath(Vector points, int posx, int posy, DrawingInstruction di) { SVGPathSegImpl pathmoveto = null; @@ -625,151 +1138,23 @@ public class PDFRenderer implements Renderer { } } - /** - * 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); - - Enumeration e = area.getChildren().elements(); - while (e.hasMoreElements()) { - Box b = (Box) e.nextElement(); - b.render(this); - } - if (area.getPosition() != Position.STATIC) { - this.currentYPosition = saveY; - this.currentAreaContainerXPosition = saveX; - } else - this.currentYPosition -= area.getHeight(); - } - - private void doFrame(Area area) { - int w, h; - int rx = this.currentAreaContainerXPosition; - w = area.getContentWidth(); - if (area instanceof BlockArea) - rx += ((BlockArea)area).getStartIndent(); - h = area.getContentHeight(); - int ry = this.currentYPosition; - ColorType bg = area.getBackgroundColor(); - - rx = rx - area.getPaddingLeft(); - ry = ry + area.getPaddingTop(); - w = w + area.getPaddingLeft() + area.getPaddingRight(); - h = h + area.getPaddingTop() + area.getPaddingBottom(); - - // I'm not sure I should have to check for bg being null - // but I do - if ((bg != null) && (bg.alpha() == 0)) { - this.addRect(rx, ry, w, -h, - new PDFColor(bg), - new PDFColor(bg)); - } - - rx = rx - area.borderWidthLeft; - ry = ry + area.borderWidthTop; - w = w + area.borderWidthLeft + area.borderWidthRight; - h = h + area.borderWidthTop + area.borderWidthBottom; - - if (area.borderWidthTop != 0) - addLine(rx, ry, rx + w, ry, - area.borderWidthTop, - new PDFColor(area.borderColorTop)); - if (area.borderWidthLeft != 0) - addLine(rx, ry, rx, ry - h, - area.borderWidthLeft, - new PDFColor(area.borderColorLeft)); - if (area.borderWidthRight != 0) - addLine(rx + w, ry, rx + w, ry - h, - area.borderWidthRight, - new PDFColor(area.borderColorRight)); - if (area.borderWidthBottom != 0) - addLine(rx, ry - h, rx + w, ry - h, - area.borderWidthBottom, - new PDFColor(area.borderColorBottom)); - - } - - - /** - * render block area to PDF - * - * @param area the block area to render - */ - public void renderBlockArea(BlockArea area) { - doFrame(area); - Enumeration e = area.getChildren().elements(); - while (e.hasMoreElements()) { - Box b = (Box) e.nextElement(); - b.render(this); - } - } - - /** - * render display space to PDF - * - * @param space the display space to render - */ - public void renderDisplaySpace(DisplaySpace space) { - int d = space.getSize(); - this.currentYPosition -= d; - } - - /** - * render image area to PDF - * - * @param area the image area to render - */ - public void renderImageArea(ImageArea area) { - // adapted from contribution by BoBoGi - int x = this.currentAreaContainerXPosition + - area.getXOffset(); - int y = this.currentYPosition; - int w = area.getContentWidth(); - int h = area.getHeight(); - - this.currentYPosition -= h; - - FopImage img = area.getImage(); - - int xObjectNum = this.pdfDoc.addImage(img); - - currentStream.add("ET\nq\n" + (((float) w) / 1000f) + " 0 0 " + - (((float) h) / 1000f) + " " + - (((float) x) / 1000f) + " " + - (((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) + 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 != null) { + 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 - + " " + (y + height) + " cm\n" + width + " 0 0 " + + + " " + (2 * y + height) + " cm\n" + width + " 0 0 " + height + " " + x + " " + y + " cm\n" + @@ -777,111 +1162,23 @@ public class PDFRenderer implements Renderer { // img.close(); } } catch(Exception e) { +e.printStackTrace(); System.err.println("could not add image to SVG: " + href); } } - /** render a foreign object area */ - public void renderForeignObjectArea(ForeignObjectArea area) - { - // if necessary need to scale and align the content - int x = this.currentAreaContainerXPosition; - switch(area.getAlign()) { - case TextAlign.START: - break; - case TextAlign.END: - break; - case TextAlign.CENTER: - case TextAlign.JUSTIFY: - break; - } - switch(area.getVerticalAlign()) { - case VerticalAlign.BASELINE: - break; - case VerticalAlign.MIDDLE: - break; - case VerticalAlign.SUB: - break; - case VerticalAlign.SUPER: - break; - case VerticalAlign.TEXT_TOP: - break; - case VerticalAlign.TEXT_BOTTOM: - break; - case VerticalAlign.TOP: - break; - case VerticalAlign.BOTTOM: - break; - } - // in general the content will not be text - currentStream.add("ET\n"); - // align and scale - currentStream.add("q\n"); - switch(area.scalingMethod()) { - case Scaling.UNIFORM: - break; - case Scaling.NON_UNIFORM: - break; - } - // if the overflow is auto (default), scroll or visible - // then the contents should not be clipped, since this - // is considered a printing medium. - switch(area.getOverflow()) { - case Overflow.VISIBLE: - case Overflow.SCROLL: - case Overflow.AUTO: - break; - case Overflow.HIDDEN: - break; - } - area.getObject().render(this); - currentStream.add("Q\n"); - currentStream.add("BT\n"); - this.currentYPosition -= area.getEffectiveHeight(); - } - - /** - * render SVG area to PDF - * - * @param area the SVG area to render - */ - public void renderSVGArea(SVGArea area) { - int x = this.currentAreaContainerXPosition; - int y = this.currentYPosition; - int w = area.getContentWidth(); - int h = area.getHeight(); - - /* - * Clip to the svg area. - * Note: To have the svg overlay (under) a text area then use - * an fo:block-container - */ - currentStream.add("q\n"); - currentStream.add(x / 1000f + " " + y / 1000f + " m\n"); - currentStream.add((x + w) / 1000f + " " + y / 1000f + " l\n"); - currentStream.add((x + w) / 1000f + " " + (y - h) / 1000f + " l\n"); - currentStream.add(x / 1000f + " " + (y - h) / 1000f + " l\n"); - currentStream.add("h\n"); - currentStream.add("W\n"); - currentStream.add("n\n"); - // transform so that the coordinates (0,0) is from the top left - // and positive is down and to the right - currentStream.add(1 + " " + 0 + " " + 0 + " " + (-1) + " " + x / 1000f + " " + y / 1000f + " cm\n"); - - // 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); + 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); } } - - currentStream.add("Q\n"); } - void handleGradient(String sp, boolean fill, GraphicImpl area) + void handleGradient(String sp, boolean fill, SVGElement area) { // should be a url to a gradient String url = (String)sp; @@ -894,7 +1191,8 @@ public class PDFRenderer implements Renderer { // local reference if(address.startsWith("#")) { // find the gradient element - GraphicImpl gi = area.locateDef(address.substring(1, address.length())); + 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; @@ -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,20 +1408,38 @@ 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)); @@ -1119,57 +1449,88 @@ public class PDFRenderer implements Renderer { } else { handleGradient((String)sp, false, area); } - } + }*/ } else { } - sp = style.get("stroke-linecap"); + sp = style.getPropertyCSSValue("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"); - } + 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"); + } + } + } } else { } - sp = style.get("stroke-linejoin"); + sp = style.getPropertyCSSValue("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"); - } + 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.get("stroke-miterlimit"); + sp = style.getPropertyCSSValue("stroke-miterlimit"); if(sp != null) { - float width; - width = ((SVGLengthImpl)sp).getValue(); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.add(pdfNumber.doubleOut(width) + " M\n"); + 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.get("stroke-width"); + sp = style.getPropertyCSSValue("stroke-width"); if(sp != null) { - float width; - width = ((SVGLengthImpl)sp).getValue(); - PDFNumber pdfNumber = new PDFNumber(); - currentStream.add(pdfNumber.doubleOut(width) + " w\n"); + 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.get("stroke-dasharray"); + sp = style.getPropertyCSSValue("stroke-dasharray"); if(sp != null) { - Vector list; + 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("0 d\n"); + } + } +/* 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"); + sp = style.getPropertyCSSValue("stroke-offset"); if(sp != null) { float width; width = ((SVGLengthImpl)sp).getValue(); @@ -1177,52 +1538,65 @@ public class PDFRenderer implements Renderer { currentStream.add("] " + pdfNumber.doubleOut(width) + " d\n"); } else { currentStream.add("] 0 d\n"); - } + }*/ } - sp = style.get("mask"); + sp = style.getPropertyCSSValue("mask"); if(sp != null) { String maskurl; - maskurl = (String)sp; +// maskurl = (String)sp; // System.out.println("mask: " + maskurl); - maskurl = maskurl.substring(1, maskurl.length()); +// maskurl = maskurl.substring(1, maskurl.length()); // get def of mask and set mask - GraphicImpl graph = null; - graph = area.locateDef(maskurl); - if(graph != null) { +// SVGElement graph = null; +// graph = area.locateDef(maskurl); +// if(graph != null) { // System.out.println("mask: " + graph); - GraphicImpl parent = graph.getGraphicParent(); - graph.setParent(area); +// SVGElement parent = graph.getGraphicParent(); +// graph.setParent(area); // renderElement(svgarea, graph, posx, posy); - graph.setParent(parent); - } +// graph.setParent(parent); +// } } return di; } // need to transform about the origin of the current object - protected void applyTransform(Vector trans) + protected void applyTransform(SVGAnimatedTransformList trans, SVGRect bbox) { + // need to rotate and scale about the bbox top left PDFNumber pdfNumber = new PDFNumber(); - for(Enumeration e = trans.elements(); e.hasMoreElements(); ) { - SVGTransform t = (SVGTransform)e.nextElement(); - SVGMatrix matrix = t.getMatrix(); + 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"); + } } - public void renderElement(SVGArea svgarea, GraphicImpl area, int posx, int posy) + public void renderElement(FontState fontState, SVGElement area, int posx, int posy) { int x = posx; int y = posy; - Hashtable style = area.oldgetStyle(); + CSSStyleDeclaration style = null; + if(area instanceof SVGStylable) + style = ((SVGStylable)area).getStyle(); DrawingInstruction di = null; currentStream.add("q\n"); - Vector trans = area.oldgetTransform(); - if(trans != null) { - applyTransform(trans); + if(area instanceof SVGTransformable) { + SVGTransformable tf = (SVGTransformable)area; + SVGAnimatedTransformList trans = tf.getTransform(); + SVGRect bbox = tf.getBBox(); + if(trans != null) { + applyTransform(trans, bbox); + } } if(style != null) { @@ -1249,7 +1623,7 @@ public class PDFRenderer implements Renderer { // 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*/); + renderText(fontState, (SVGTextElementImpl)area, 0, 0/*, di*/); currentStream.add("ET\n"); // currentStream.add("Q\n"); } else if (area instanceof SVGCircleElement) { @@ -1272,44 +1646,38 @@ public class PDFRenderer implements Renderer { } else if (area instanceof SVGPolygonElementImpl) { addPolyline(((SVGPolygonElementImpl)area).points, posx, posy, di, true); } else if (area instanceof SVGGElementImpl) { - renderGArea(svgarea, (SVGGElementImpl)area, x, y); + 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()); - GraphicImpl graph = null; - graph = area.locateDef(ref); + 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. - GraphicImpl parent = graph.getGraphicParent(); - graph.setParent(area); +// 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(svgarea, graph, posx, posy); - graph.setParent(parent); + renderElement(fontState, 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) { + 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! - 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); - } - } + 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 GraphicImpl) { + if(n instanceof SVGElement) { if(n instanceof GraphicElement) { SVGRect rect = ((GraphicElement)n).getBBox(); if(rect != null) { @@ -1322,28 +1690,23 @@ public class PDFRenderer implements Renderer { currentAnnotList = null; */ } } - renderElement(svgarea, (GraphicImpl)n, posx, posy); + renderElement(fontState, (SVGElement)n, posx, posy); } } } else if (area instanceof SVGSwitchElement) { - handleSwitchElement(svgarea, posx, posy, (SVGSwitchElement)area); + handleSwitchElement(fontState, 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) + public void renderText(FontState fontState, 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(); + CSSStyleDeclaration styles; + styles = tg.getStyle(); applyStyle(tg, styles); // apply transform // text has a Tm and need to handle each element @@ -1354,24 +1717,42 @@ public class PDFRenderer implements Renderer { + " " + pdfNumber.doubleOut(matrix.getC()) + " " + pdfNumber.doubleOut(-matrix.getD()) + " "); - String fontFamily; - fontFamily = (String)styles.get("font-family"); + 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; - fontStyle = (String)styles.get("font-style"); + 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; - fontWeight = (String)styles.get("font-weight"); + 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(); - SVGLength len; - len = (SVGLength)styles.get("font-size"); float fontSize; - fontSize = fontState.getFontSize() / 1000f; - if(len != null) - fontSize = len.getValue(); + 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, @@ -1385,78 +1766,102 @@ public class PDFRenderer implements Renderer { 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 " - + "(" + str + ") Tj\n"); - for(int count = 0; count < str.length(); count++) { - currentX += fs.width(str.charAt(count)) / 1000f; - } - currentX += fs.width(' ') / 1000f; + + "("); + 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; - GraphicImpl graph = null; - graph = tpg.locateDef(ref); + 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); +// GraphicImpl parent = graph.getGraphicParent(); +// graph.setParent(tpg); // set text path?? // how should this work - graph.setParent(parent); +// 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); + SVGElement graph = null; +// graph = trg.locateDef(ref); if(graph != null && graph instanceof SVGTextElementImpl) { - GraphicImpl parent = graph.getGraphicParent(); - graph.setParent(trg); +// GraphicImpl parent = graph.getGraphicParent(); +// graph.setParent(trg); SVGTextElementImpl te = (SVGTextElementImpl)graph; - renderText(svgarea, te, (int)(x + tx), (int)(y + ty)); - graph.setParent(parent); + renderText(fs, 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(); + styles = tsg.getStyle(); applyStyle(tsg, styles); boolean changed = false; - String newprop; - newprop = (String)styles.get("font-family"); + 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; } - newprop = (String)styles.get("font-style"); + 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; } - newprop = (String)styles.get("font-weight"); + 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; } - len = (SVGLengthImpl)styles.get("font-size"); - if(len != null) { - float newSize = len.getValue(); - if(fontSize != newSize) { - fontSize = newSize; - 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)); @@ -1466,343 +1871,190 @@ public class PDFRenderer implements Renderer { currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n"); } - if(tsg.ylist != null) { - ty = ((Float)tsg.ylist.elementAt(0)).floatValue(); - } - 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++; + 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(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"); + if(tsg.dylist.size() > charPos) { + ypos = ypos + ((Float)tsg.dylist.elementAt(charPos)).floatValue(); } - } 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++; + if(tsg.xlist.size() > charPos) { + xpos = x + tx + ((Float)tsg.xlist.elementAt(charPos)).floatValue(); } - 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"); + 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; } - } 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)); - }*/ } - currentX += fs.width(' ') / 1000f; + 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); } } } - public void renderGArea(SVGArea svgarea, SVGGElementImpl area, int posx, int posy) - { - Enumeration e = area.getChildren().elements(); - while (e.hasMoreElements()) { - Object o = e.nextElement(); - if(o instanceof GraphicImpl) { - renderElement(svgarea, (GraphicImpl)o, posx, posy); - } - } - } - - void handleSwitchElement(SVGArea svgarea, int posx, int posy, SVGSwitchElement ael) + protected float addSVGStr(FontState fs, float currentX, String str, boolean spacing) { - 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 + 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; } - /** - * 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; - } - } - } - 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); - } } |