You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by jo...@locus.apache.org on 2000/06/21 03:47:19 UTC

cvs commit: xml-fop/src/org/apache/fop/render/pdf PDFRenderer.java

jordan      00/06/20 18:47:19

  Modified:    src/org/apache/fop/render/pdf PDFRenderer.java
  Log:
  Added internal-link functionality
  
  Revision  Changes    Path
  1.17      +575 -564  xml-fop/src/org/apache/fop/render/pdf/PDFRenderer.java
  
  Index: PDFRenderer.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/pdf/PDFRenderer.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- PDFRenderer.java	2000/05/23 09:24:55	1.16
  +++ PDFRenderer.java	2000/06/21 01:47:18	1.17
  @@ -1,564 +1,575 @@
  -/*-- $Id: PDFRenderer.java,v 1.16 2000/05/23 09:24:55 eschaeffer Exp $ -- 
  -
  - ============================================================================
  -				   The Apache Software License, Version 1.1
  - ============================================================================
  - 
  -	Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
  - 
  - Redistribution and use in source and binary forms, with or without modifica-
  - tion, are permitted provided that the following conditions are met:
  - 
  - 1. Redistributions of	source code must  retain the above copyright  notice,
  -	this list of conditions and the following disclaimer.
  - 
  - 2. Redistributions in binary form must reproduce the above copyright notice,
  -	this list of conditions and the following disclaimer in the documentation
  -	and/or other materials provided with the distribution.
  - 
  - 3. The end-user documentation included with the redistribution, if any, must
  -	include  the following	acknowledgment:  "This product includes  software
  -	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
  -	Alternately, this  acknowledgment may  appear in the software itself,  if
  -	and wherever such third-party acknowledgments normally appear.
  - 
  - 4. The names "FOP" and  "Apache Software Foundation"  must not be used to
  -	endorse  or promote  products derived  from this  software without	prior
  -	written permission. For written permission, please contact
  -	apache@apache.org.
  - 
  - 5. Products  derived from this software may not  be called "Apache", nor may
  -	"Apache" appear  in their name,  without prior written permission  of the
  -	Apache Software Foundation.
  - 
  - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  - FITNESS  FOR A PARTICULAR	PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  - APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
  - INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
  - DING, BUT NOT LIMITED TO, PROCUREMENT	OF SUBSTITUTE GOODS OR SERVICES; LOSS
  - OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)	HOWEVER CAUSED AND ON
  - ANY  THEORY OF LIABILITY,	WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
  - (INCLUDING  NEGLIGENCE OR	OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
  - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  - 
  - This software	consists of voluntary contributions made  by many individuals
  - on  behalf of the Apache Software	Foundation and was	originally created by
  - James Tauber <jt...@jtauber.com>. For more  information on the Apache 
  - Software Foundation, please see <http://www.apache.org/>.
  - 
  - */
  -
  -package org.apache.fop.render.pdf;
  -
  -// FOP
  -import org.apache.fop.render.Renderer;
  -import org.apache.fop.image.ImageArea;
  -import org.apache.fop.image.FopImage;
  -import org.apache.fop.fo.properties.*;
  -import org.apache.fop.layout.*;
  -import org.apache.fop.datatypes.*;
  -import org.apache.fop.svg.*;
  -import org.apache.fop.pdf.*;
  -
  -// Java
  -import java.io.IOException;
  -import java.io.PrintWriter;
  -import java.util.Enumeration;
  -import java.awt.Rectangle;
  -import java.util.Vector;
  -
  -/**
  - * Renderer that renders areas to PDF
  - */
  -public class PDFRenderer implements Renderer {
  -	
  -	/** the PDF Document being created */
  -	protected PDFDocument pdfDoc;
  -
  -	/** the /Resources object of the PDF document being created */
  -	protected PDFResources pdfResources;
  -
  -	/** the current stream to add PDF commands to */
  -	PDFStream currentStream;
  -
  -	/** the current annotation list to add annotations to */
  -	PDFAnnotList currentAnnotList;
  -
  -	/** the current page to add annotations to */
  -	PDFPage currentPage;
  -
  -	/** the current (internal) font name */
  -	protected String currentFontName;
  -
  -	/** the current font size in millipoints */
  -	protected int currentFontSize;
  -
  -	/** the current color/gradient for borders, letters, etc. */
  -	protected PDFPathPaint currentStroke = null;
  -	
  -	/** the current color/gradient to fill shapes with */
  -	protected PDFPathPaint currentFill = null;
  -	
  -	/** the current colour's red component */
  -	protected float currentRed = 0;
  -
  -	/** the current colour's green component */
  -	protected float currentGreen = 0;
  -
  -	/** the current colour's blue component */
  -	protected float currentBlue = 0;
  -	
  -	/** the current vertical position in millipoints from bottom */
  -	protected int currentYPosition = 0;
  -
  -	/** the current horizontal position in millipoints from left */
  -	protected int currentXPosition = 0;
  -
  -	/** the horizontal position of the current area container */
  -	private int currentAreaContainerXPosition = 0;
  -
  -	/**
  -	 * create the PDF renderer
  -	 */
  -	public PDFRenderer() {
  -	this.pdfDoc = new PDFDocument();
  -	}
  -
  -	/**
  -	 * set the PDF document's producer
  -	 *
  -	 * @param producer string indicating application producing PDF
  -	 */
  -	public void setProducer(String producer) {
  -	this.pdfDoc.setProducer(producer);
  -	}
  -
  -	/**
  -	 * render the areas into PDF
  -	 *
  -	 * @param areaTree the laid-out area tree
  -	 * @param writer the PrintWriter to write the PDF with
  -	 */
  -	public void render(AreaTree areaTree, PrintWriter writer)
  -	throws IOException {
  -	System.err.println("rendering areas to PDF");
  -	this.pdfResources = this.pdfDoc.getResources();
  -	Enumeration e = areaTree.getPages().elements();
  -	while (e.hasMoreElements()) {
  -		this.renderPage((Page) e.nextElement());
  -	}
  -	System.err.println("writing out PDF");
  -	this.pdfDoc.output(writer);
  -	}
  -
  -	/**
  -	 * 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 stroke the stroke color/gradient
  -	 */
  -	protected void addLine(int x1, int y1, int x2, int y2, int th,
  -			PDFPathPaint stroke) {
  -		
  -	currentStream.add(stroke.getColorSpaceOut(false)
  -			  + (x1/1000f) + " " + (y1/1000f) + " m "
  -			  + (x2/1000f) + " " + (y2/1000f) + " l "
  -			  + (th/1000f) + " w S\n"
  -			  + "0 0 0 RG\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(stroke.getColorSpaceOut(false)
  -			  + (x/1000f) + " " + (y/1000f) + " "
  -			  + (w/1000f) + " " + (h/1000f) + " re S\n"
  -			  + "0 0 0 RG\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(fill.getColorSpaceOut(true)
  -			  + stroke.getColorSpaceOut(false)
  -			  + (x/1000f) + " " + (y/1000f) + " "
  -			  + (w/1000f) + " " + (h/1000f) + " re S\n"
  -			  + (x/1000f) + " " + (y/1000f) + " "
  -			  + (w/1000f) + " " + (h/1000f) + " re f\n"
  -			  + "0 0 0 RG 0 0 0 rg\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 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();
  -	this.currentYPosition -= h;
  -	Enumeration e = area.getChildren().elements();
  -	while (e.hasMoreElements()) {
  -		Object o = e.nextElement();
  -		if (o instanceof RectGraphic) {
  -		int rx = ((RectGraphic)o).x;
  -		int ry = ((RectGraphic)o).y;
  -		int rw = ((RectGraphic)o).width;
  -		int rh = ((RectGraphic)o).height;
  -		addRect(x+rx,y-ry,rw,-rh,new PDFColor(0,0,0));
  -		} else if (o instanceof LineGraphic) {
  -		int x1 = ((LineGraphic)o).x1;
  -		int y1 = ((LineGraphic)o).y1;
  -		int x2 = ((LineGraphic)o).x2;
  -		int y2 = ((LineGraphic)o).y2;
  -		addLine(x+x1,y-y1,x+x2,y-y2,0,new PDFColor(0,0,0));
  -		} else if (o instanceof TextGraphic) {
  -		int tx = ((TextGraphic)o).x;
  -		int ty = ((TextGraphic)o).y;
  -		String s = ((TextGraphic)o).s;
  -		currentStream.add("1 0 0 1 "
  -				  + ((x+tx)/1000f) + " "
  -				  + ((y-ty)/1000f) + " Tm " 
  -				  + "(" + s + ") Tj\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 = 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);
  -
  -	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();
  -		Enumeration f = linkSet.getRects().elements();
  -		while (f.hasMoreElements()) {
  -			LinkedRectangle lrect = (LinkedRectangle) f.nextElement();
  -			currentAnnotList.addLink(
  -				this.pdfDoc.makeLink(lrect.getRectangle(), dest));
  -		}
  -		}
  -	} 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);
  -	}
  -}
  -
  +/*-- $Id: PDFRenderer.java,v 1.17 2000/06/21 01:47:18 jordan Exp $ -- 
  +
  + ============================================================================
  +				   The Apache Software License, Version 1.1
  + ============================================================================
  + 
  +	Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
  + 
  + Redistribution and use in source and binary forms, with or without modifica-
  + tion, are permitted provided that the following conditions are met:
  + 
  + 1. Redistributions of	source code must  retain the above copyright  notice,
  +	this list of conditions and the following disclaimer.
  + 
  + 2. Redistributions in binary form must reproduce the above copyright notice,
  +	this list of conditions and the following disclaimer in the documentation
  +	and/or other materials provided with the distribution.
  + 
  + 3. The end-user documentation included with the redistribution, if any, must
  +	include  the following	acknowledgment:  "This product includes  software
  +	developed  by the  Apache Software Foundation  (http://www.apache.org/)."
  +	Alternately, this  acknowledgment may  appear in the software itself,  if
  +	and wherever such third-party acknowledgments normally appear.
  + 
  + 4. The names "FOP" and  "Apache Software Foundation"  must not be used to
  +	endorse  or promote  products derived  from this  software without	prior
  +	written permission. For written permission, please contact
  +	apache@apache.org.
  + 
  + 5. Products  derived from this software may not  be called "Apache", nor may
  +	"Apache" appear  in their name,  without prior written permission  of the
  +	Apache Software Foundation.
  + 
  + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  + FITNESS  FOR A PARTICULAR	PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  + APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
  + INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
  + DING, BUT NOT LIMITED TO, PROCUREMENT	OF SUBSTITUTE GOODS OR SERVICES; LOSS
  + OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)	HOWEVER CAUSED AND ON
  + ANY  THEORY OF LIABILITY,	WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
  + (INCLUDING  NEGLIGENCE OR	OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
  + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  + 
  + This software	consists of voluntary contributions made  by many individuals
  + on  behalf of the Apache Software	Foundation and was	originally created by
  + James Tauber <jt...@jtauber.com>. For more  information on the Apache 
  + Software Foundation, please see <http://www.apache.org/>.
  + 
  + */
  +
  +package org.apache.fop.render.pdf;
  +
  +// FOP
  +import org.apache.fop.render.Renderer;
  +import org.apache.fop.image.ImageArea;
  +import org.apache.fop.image.FopImage;
  +import org.apache.fop.apps.FOPException;
  +import org.apache.fop.fo.properties.*;
  +import org.apache.fop.layout.*;
  +import org.apache.fop.datatypes.*;
  +import org.apache.fop.svg.*;
  +import org.apache.fop.pdf.*;
  +
  +// Java
  +import java.io.IOException;
  +import java.io.PrintWriter;
  +import java.util.Enumeration;
  +import java.awt.Rectangle;
  +import java.util.Vector;
  +
  +/**
  + * Renderer that renders areas to PDF
  + */
  +public class PDFRenderer implements Renderer {
  +	
  +	/** the PDF Document being created */
  +	protected PDFDocument pdfDoc;
  +
  +	/** the /Resources object of the PDF document being created */
  +	protected PDFResources pdfResources;
  +
  +	/** the current stream to add PDF commands to */
  +	PDFStream currentStream;
  +
  +	/** the current annotation list to add annotations to */
  +	PDFAnnotList currentAnnotList;
  +
  +	/** the current page to add annotations to */
  +	PDFPage currentPage;
  +
  +	/** the current (internal) font name */
  +	protected String currentFontName;
  +
  +	/** the current font size in millipoints */
  +	protected int currentFontSize;
  +
  +	/** the current color/gradient for borders, letters, etc. */
  +	protected PDFPathPaint currentStroke = null;
  +	
  +	/** the current color/gradient to fill shapes with */
  +	protected PDFPathPaint currentFill = null;
  +	
  +	/** the current colour's red component */
  +	protected float currentRed = 0;
  +
  +	/** the current colour's green component */
  +	protected float currentGreen = 0;
  +
  +	/** the current colour's blue component */
  +	protected float currentBlue = 0;
  +	
  +	/** the current vertical position in millipoints from bottom */
  +	protected int currentYPosition = 0;
  +
  +	/** the current horizontal position in millipoints from left */
  +	protected int currentXPosition = 0;
  +
  +	/** the horizontal position of the current area container */
  +	private int currentAreaContainerXPosition = 0;
  +
  +	/**
  +	 * create the PDF renderer
  +	 */
  +	public PDFRenderer() {
  +	this.pdfDoc = new PDFDocument();
  +	}
  +
  +	/**
  +	 * set the PDF document's producer
  +	 *
  +	 * @param producer string indicating application producing PDF
  +	 */
  +	public void setProducer(String producer) {
  +	this.pdfDoc.setProducer(producer);
  +	}
  +
  +	/**
  +	 * render the areas into PDF
  +	 *
  +	 * @param areaTree the laid-out area tree
  +	 * @param writer the PrintWriter to write the PDF with
  +	 */	
  +        public void render(AreaTree areaTree, PrintWriter writer)
  +        throws IOException, FOPException {      
  +            System.err.println("rendering areas to PDF");
  +            IDReferences idReferences=areaTree.getIDReferences();           
  +            this.pdfResources = this.pdfDoc.getResources();            
  +            this.pdfDoc.setIDReferences(idReferences);
  +            Enumeration e = areaTree.getPages().elements(); 
  +            while ( e.hasMoreElements() ) {
  +                this.renderPage((Page) e.nextElement());                
  +            }
  +    
  +            if ( !idReferences.isEveryIdValid() ) {
  +                throw new FOPException("The id \""+idReferences.getNextInvalidId()+"\" was referenced but does not exist\n");            
  +            }
  +    
  +            System.err.println("writing out PDF");
  +            this.pdfDoc.output(writer);
  +        }
  +
  +
  +
  +	/**
  +	 * 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 stroke the stroke color/gradient
  +	 */
  +	protected void addLine(int x1, int y1, int x2, int y2, int th,
  +			PDFPathPaint stroke) {
  +		
  +	currentStream.add(stroke.getColorSpaceOut(false)
  +			  + (x1/1000f) + " " + (y1/1000f) + " m "
  +			  + (x2/1000f) + " " + (y2/1000f) + " l "
  +			  + (th/1000f) + " w S\n"
  +			  + "0 0 0 RG\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(stroke.getColorSpaceOut(false)
  +			  + (x/1000f) + " " + (y/1000f) + " "
  +			  + (w/1000f) + " " + (h/1000f) + " re S\n"
  +			  + "0 0 0 RG\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(fill.getColorSpaceOut(true)
  +			  + stroke.getColorSpaceOut(false)
  +			  + (x/1000f) + " " + (y/1000f) + " "
  +			  + (w/1000f) + " " + (h/1000f) + " re S\n"
  +			  + (x/1000f) + " " + (y/1000f) + " "
  +			  + (w/1000f) + " " + (h/1000f) + " re f\n"
  +			  + "0 0 0 RG 0 0 0 rg\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 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();
  +	this.currentYPosition -= h;
  +	Enumeration e = area.getChildren().elements();
  +	while (e.hasMoreElements()) {
  +		Object o = e.nextElement();
  +		if (o instanceof RectGraphic) {
  +		int rx = ((RectGraphic)o).x;
  +		int ry = ((RectGraphic)o).y;
  +		int rw = ((RectGraphic)o).width;
  +		int rh = ((RectGraphic)o).height;
  +		addRect(x+rx,y-ry,rw,-rh,new PDFColor(0,0,0));
  +		} else if (o instanceof LineGraphic) {
  +		int x1 = ((LineGraphic)o).x1;
  +		int y1 = ((LineGraphic)o).y1;
  +		int x2 = ((LineGraphic)o).x2;
  +		int y2 = ((LineGraphic)o).y2;
  +		addLine(x+x1,y-y1,x+x2,y-y2,0,new PDFColor(0,0,0));
  +		} else if (o instanceof TextGraphic) {
  +		int tx = ((TextGraphic)o).x;
  +		int ty = ((TextGraphic)o).y;
  +		String s = ((TextGraphic)o).s;
  +		currentStream.add("1 0 0 1 "
  +				  + ((x+tx)/1000f) + " "
  +				  + ((y-ty)/1000f) + " Tm " 
  +				  + "(" + s + ") Tj\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 = 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);
  +	}
  +}
  +