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 je...@apache.org on 2003/03/11 09:42:24 UTC
cvs commit: xml-fop/src/org/apache/fop/render/ps PSTextPainter.java PSXMLHandler.java PSRenderer.java PSProcSets.java PSGraphics2D.java
jeremias 2003/03/11 00:42:24
Modified: src/org/apache/fop/render/ps PSXMLHandler.java
PSRenderer.java PSProcSets.java PSGraphics2D.java
Added: src/org/apache/fop/render/ps PSTextPainter.java
Log:
Port of the PDF TextPainter to PostScript.
Support for SEG_QUADTO (curves).
Some support for viewport traits (background and borders).
Submitted by: Zhong Yi <yi...@yahoo.com>
Revision Changes Path
1.4 +16 -11 xml-fop/src/org/apache/fop/render/ps/PSXMLHandler.java
Index: PSXMLHandler.java
===================================================================
RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSXMLHandler.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- PSXMLHandler.java 7 Mar 2003 09:46:30 -0000 1.3
+++ PSXMLHandler.java 11 Mar 2003 08:42:24 -0000 1.4
@@ -50,24 +50,27 @@
*/
package org.apache.fop.render.ps;
-import org.apache.fop.render.XMLHandler;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.svg.SVGUserAgent;
-import org.apache.fop.layout.FontInfo;
+// Java
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+// DOM
import org.w3c.dom.Document;
+import org.w3c.dom.svg.SVGDocument;
+import org.w3c.dom.svg.SVGSVGElement;
+// Batik
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.ViewBox;
-
import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.TextPainter;
-import org.w3c.dom.svg.SVGDocument;
-import org.w3c.dom.svg.SVGSVGElement;
-
-import java.awt.geom.AffineTransform;
-import java.io.IOException;
+// FOP
+import org.apache.fop.render.XMLHandler;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.svg.SVGUserAgent;
+import org.apache.fop.layout.FontInfo;
/**
* PostScript XML handler.
@@ -300,7 +303,9 @@
transform.translate(xOffset / 1000f, yOffset / 1000f);
//aBridge.setCurrentTransform(transform);
//ctx.putBridge(aBridge);
-
+
+ TextPainter textPainter = new PSTextPainter(psInfo.getFontInfo());
+ ctx.setTextPainter(textPainter);
GraphicsNode root;
try {
root = builder.build(ctx, doc);
1.31 +197 -5 xml-fop/src/org/apache/fop/render/ps/PSRenderer.java
Index: PSRenderer.java
===================================================================
RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSRenderer.java,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- PSRenderer.java 5 Mar 2003 20:38:26 -0000 1.30
+++ PSRenderer.java 11 Mar 2003 08:42:24 -0000 1.31
@@ -59,6 +59,9 @@
import java.util.Map;
// FOP
+import org.apache.fop.fo.properties.BackgroundRepeat;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.RegionViewport;
import org.apache.fop.apps.FOPException;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockViewport;
@@ -73,9 +76,12 @@
import org.apache.fop.layout.FontInfo;
import org.apache.fop.render.AbstractRenderer;
import org.apache.fop.render.RendererContext;
-import org.w3c.dom.Document;
+import org.apache.fop.image.FopImage;
+import org.apache.fop.image.ImageFactory;
+import org.apache.fop.traits.BorderProps;
+import org.w3c.dom.Document;
/**
* Renderer that renders to PostScript.
* <br>
@@ -416,14 +422,15 @@
{page.getPageNumber(),
new Integer(this.currentPageNumber)});
final Integer zero = new Integer(0);
- final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth() / 1000f));
- final Long pageheight = new Long(Math.round(page.getViewArea().getHeight() / 1000f));
+ final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth()));
+ final Long pageheight = new Long(Math.round(page.getViewArea().getHeight()));
gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[]
{zero, zero, pagewidth, pageheight});
gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP);
gen.writeln("FOPFonts begin");
- concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue());
gen.writeln("0.001 0.001 scale");
+ concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue());
+
gen.writeDSCComment(DSCConstants.END_PAGE_SETUP);
//Process page
@@ -629,7 +636,7 @@
saveGraphicsState();
// multiply with current CTM
- //currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n");
+ //writeln(CTMHelper.toPDFString(ctm) + " cm\n");
final double matrix[] = ctm.toArray();
concatMatrix(matrix);
@@ -646,7 +653,190 @@
//currentState.pop();
}
+ /**
+ * Handle the viewport traits.
+ * This is used to draw the traits for a viewport.
+ *
+ * @param region the viewport region to handle
+ */
+ protected void handleViewportTraits(RegionViewport region) {
+ currentFontName = "";
+ float startx = 0;
+ float starty = 0;
+ Rectangle2D viewArea = region.getViewArea();
+ float width = (float)(viewArea.getWidth());
+ float height = (float)(viewArea.getHeight());
+ /*
+ Trait.Background back;
+ back = (Trait.Background)region.getTrait(Trait.BACKGROUND);
+ */
+ drawBackAndBorders(region, startx, starty, width, height);
+ }
+
+ /**
+ * Handle block traits.
+ * The block could be any sort of block with any positioning
+ * so this should render the traits such as border and background
+ * in its position.
+ *
+ * @param block the block to render the traits
+ */
+ protected void handleBlockTraits(Block block) {
+ float startx = currentIPPosition;
+ float starty = currentBPPosition;
+ drawBackAndBorders(block, startx, starty,
+ block.getWidth(), block.getHeight());
+ }
+
+ /**
+ * Draw the background and borders.
+ * This draws the background and border traits for an area given
+ * the position.
+ *
+ * @param block the area to get the traits from
+ * @param startx the start x position
+ * @param starty the start y position
+ * @param width the width of the area
+ * @param height the height of the area
+ */
+ protected void drawBackAndBorders(Area block,
+ float startx, float starty,
+ float width, float height) {
+ // draw background then border
+
+ boolean started = false;
+ Trait.Background back;
+ back = (Trait.Background)block.getTrait(Trait.BACKGROUND);
+ if (back != null) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+
+ if (back.getColor() != null) {
+ updateColor(back.getColor(), true, null);
+ writeln(startx + " " + starty + " "
+ + width + " " + height + " rectfill");
+ }
+ if (back.getURL() != null) {
+ ImageFactory fact = ImageFactory.getInstance();
+ FopImage fopimage = fact.getImage(back.getURL(), userAgent);
+ if (fopimage != null && fopimage.load(FopImage.DIMENSIONS, userAgent)) {
+ if (back.getRepeat() == BackgroundRepeat.REPEAT) {
+ // create a pattern for the image
+ } else {
+ // place once
+ Rectangle2D pos;
+ pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000,
+ (starty + back.getVertical()) * 1000,
+ fopimage.getWidth() * 1000,
+ fopimage.getHeight() * 1000);
+ // putImage(back.url, pos);
+ }
+ }
+ }
+ }
+
+ BorderProps bps = (BorderProps)block.getTrait(Trait.BORDER_BEFORE);
+ if (bps != null) {
+ float endx = startx + width;
+
+ if (!started) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+
+ drawLine(startx, starty + bwidth / 2, endx, starty + bwidth / 2);
+ }
+ bps = (BorderProps)block.getTrait(Trait.BORDER_START);
+ if (bps != null) {
+ float endy = starty + height;
+
+ if (!started) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+
+ drawLine(startx + bwidth / 2, starty, startx + bwidth / 2, endy);
+ }
+ bps = (BorderProps)block.getTrait(Trait.BORDER_AFTER);
+ if (bps != null) {
+ float sy = starty + height;
+ float endx = startx + width;
+
+ if (!started) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+
+ drawLine(startx, sy - bwidth / 2, endx, sy - bwidth / 2);
+ }
+ bps = (BorderProps)block.getTrait(Trait.BORDER_END);
+ if (bps != null) {
+ float sx = startx + width;
+ float endy = starty + height;
+
+ if (!started) {
+ started = true;
+ // closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+ drawLine(sx - bwidth / 2, starty, sx - bwidth / 2, endy);
+ }
+ if (started) {
+ //restoreGraphicsState();
+ beginTextObject();
+ // font last set out of scope in text section
+ currentFontName = "";
+ }
+ }
+
+ /**
+ * Draw a line.
+ *
+ * @param startx the start x position
+ * @param starty the start y position
+ * @param endx the x end position
+ * @param endy the y end position
+ */
+ private void drawLine(float startx, float starty, float endx, float endy) {
+ writeln(startx + " " + starty + " M ");
+ writeln(endx + " " + endy + " lineto");
+ }
+ private void updateColor(ColorType col, boolean fill, StringBuffer pdf) {
+ writeln(gen.formatDouble(col.getRed()) + " "
+ + gen.formatDouble(col.getGreen()) + " "
+ + gen.formatDouble(col.getBlue()) + " setrgbcolor");
+ }
+
+ private void updateFont(String name, int size, StringBuffer pdf) {
+
+ }
+
/**
* @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
*/
@@ -677,6 +867,8 @@
new Integer(currentBlockIPPosition + (int) pos.getX()));
context.setProperty(PSXMLHandler.PS_YPOS,
new Integer(currentBPPosition + (int) pos.getY()));
+ //context.setProperty("strokeSVGText", options.get("strokeSVGText"));
+
/*
context.setProperty(PDFXMLHandler.PDF_DOCUMENT, pdfDoc);
context.setProperty(PDFXMLHandler.OUTPUT_STREAM, ostream);
1.3 +14 -1 xml-fop/src/org/apache/fop/render/ps/PSProcSets.java
Index: PSProcSets.java
===================================================================
RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSProcSets.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- PSProcSets.java 7 Mar 2003 09:46:30 -0000 1.2
+++ PSProcSets.java 11 Mar 2003 08:42:24 -0000 1.3
@@ -141,7 +141,20 @@
gen.writeln(" Tt setlinewidth stroke");
gen.writeln(" grestore");
gen.writeln("} bd");
-
+
+ gen.writeln("/QUADTO {");
+ gen.writeln("/Y22 exch store");
+ gen.writeln("/X22 exch store");
+ gen.writeln("/Y21 exch store");
+ gen.writeln("/X21 exch store");
+ gen.writeln("currentpoint");
+ gen.writeln("/Y21 load 2 mul add 3 div exch");
+ gen.writeln("/X21 load 2 mul add 3 div exch");
+ gen.writeln("/X21 load 2 mul /X22 load add 3 div");
+ gen.writeln("/Y21 load 2 mul /Y22 load add 3 div");
+ gen.writeln("/X22 load /Y22 load curveto");
+ gen.writeln("} bd");
+
gen.writeln("%%EndResource");
}
1.11 +96 -42 xml-fop/src/org/apache/fop/render/ps/PSGraphics2D.java
Index: PSGraphics2D.java
===================================================================
RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSGraphics2D.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- PSGraphics2D.java 7 Mar 2003 09:46:30 -0000 1.10
+++ PSGraphics2D.java 11 Mar 2003 08:42:24 -0000 1.11
@@ -114,7 +114,10 @@
/** Currently valid FontState */
protected FontState fontState;
-
+
+ /** Overriding FontState */
+ protected FontState overrideFontState = null;
+
/**
* the current (internal) font name
*/
@@ -501,8 +504,9 @@
Shape imclip = getClip();
writeClip(imclip);
Color c = getColor();
- gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue()
- + " setrgbcolor");
+ gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " "
+ + gen.formatDouble(c.getGreen() / 255.0) + " "
+ + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor");
applyPaint(getPaint(), false);
applyStroke(getStroke());
@@ -533,10 +537,10 @@
+ " M");
break;
case PathIterator.SEG_QUADTO:
- // psRenderer.write((1000 * PDFNumber.doubleOut(vals[0])) +
- // " " + (1000 * PDFNumber.doubleOut(vals[1])) + " " +
- // (1000 * PDFNumber.doubleOut(vals[2])) + " " +
- // (1000 * PDFNumber.doubleOut(vals[3])) + " y\n");
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
break;
case PathIterator.SEG_CLOSE:
gen.writeln("closepath");
@@ -585,10 +589,10 @@
+ " M");
break;
case PathIterator.SEG_QUADTO:
- // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) +
- // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " +
- // 1000 * PDFNumber.doubleOut(vals[2]) + " " +
- // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n");
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
break;
case PathIterator.SEG_CLOSE:
gen.writeln("closepath");
@@ -803,32 +807,73 @@
* @see #setClip
*/
public void drawString(String s, float x, float y) {
- try {
- System.out.println("drawString(String)");
- gen.writeln("BT");
- Shape imclip = getClip();
- writeClip(imclip);
- Color c = getColor();
- gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue()
- + " setrgbcolor");
-
- AffineTransform trans = getTransform();
- trans.translate(x, y);
- double[] vals = new double[6];
- trans.getMatrix(vals);
-
- gen.writeln(gen.formatDouble(vals[0]) + " "
- + gen.formatDouble(vals[1]) + " "
- + gen.formatDouble(vals[2]) + " "
- + gen.formatDouble(vals[3]) + " "
- + gen.formatDouble(vals[4]) + " "
- + gen.formatDouble(vals[5]) + " "
- + gen.formatDouble(vals[6]) + " Tm [" + s + "]");
-
- gen.writeln("ET");
- } catch (IOException ioe) {
- handleIOException(ioe);
+ try {
+ if (overrideFontState == null) {
+ Font gFont = getFont();
+ String n = gFont.getFamily();
+ if (n.equals("sanserif")) {
+ n = "sans-serif";
+ }
+ int siz = gFont.getSize();
+ String style = gFont.isItalic() ? "italic" : "normal";
+ String weight = gFont.isBold() ? "bold" : "normal";
+
+ //try {
+ //fontState = new FontState(n, fontState.getFontMetrics(),siz);
+ //} catch (org.apache.fop.apps.FOPException fope) {
+ //fope.printStackTrace();
+ //}
+ } else {
+ fontState = overrideFontState;
+ overrideFontState = null;
}
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ gen.writeln(c.getRed() / 255.0 + " "
+ + c.getGreen() / 255.0 + " "
+ + c.getBlue() / 255.0 + " setrgbcolor");
+
+ AffineTransform trans = getTransform();
+ trans.translate(x, y);
+ double[] vals = new double[6];
+ trans.getMatrix(vals);
+ gen.writeln(gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5]) + " moveto ");
+ //String fontWeight = fontState.getFontWeight();
+ StringBuffer sb = new StringBuffer();
+
+ int l = s.length();
+
+ if ((currentFontName != fontState.getFontName())
+ || (currentFontSize != fontState.getFontSize())) {
+ gen.writeln(fontState.getFontName() + " " + fontState.getFontSize() + " F");
+ currentFontName = fontState.getFontName();
+ currentFontSize = fontState.getFontSize();
+ }
+ for (int i = 0; i < l; i++) {
+ char ch = s.charAt(i);
+ char mch = fontState.mapChar(ch);
+ if (mch > 127) {
+ sb = sb.append("\\" + Integer.toOctalString(mch));
+ } else {
+ String escape = "\\()[]{}";
+ if (escape.indexOf(mch) >= 0) {
+ sb.append("\\");
+ }
+ sb = sb.append(mch);
+ }
+ }
+
+ String psString = null;
+ psString = " (" + sb.toString() + ") " + " t ";
+
+ gen.writeln(" 1.0 -1.0 scale");
+ gen.writeln(psString);
+ gen.writeln(" 1.0 -1.0 scale");
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
}
/**
@@ -917,8 +962,9 @@
Shape imclip = getClip();
writeClip(imclip);
Color c = getColor();
- gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue()
- + " setrgbcolor");
+ gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " "
+ + gen.formatDouble(c.getGreen() / 255.0) + " "
+ + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor");
applyPaint(getPaint(), true);
@@ -948,10 +994,10 @@
+ " M");
break;
case PathIterator.SEG_QUADTO:
- // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) +
- // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " +
- // 1000 * PDFNumber.doubleOut(vals[2]) + " " +
- // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n");
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
break;
case PathIterator.SEG_CLOSE:
gen.writeln("closepath");
@@ -1021,6 +1067,14 @@
fmg = bi.createGraphics();
}
+ /**
+ * Sets the overrideing font state.
+ * @param infont FontState to set
+ */
+ public void setOverrideFontState(FontState infont) {
+ overrideFontState = infont;
+ }
+
/**
* Gets the font metrics for the specified font.
* @return the font metrics for the specified font.
1.1 xml-fop/src/org/apache/fop/render/ps/PSTextPainter.java
Index: PSTextPainter.java
===================================================================
/*
* $Id$
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 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.ps;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.Font;
import java.text.AttributedCharacterIterator;
import java.awt.font.TextAttribute;
import java.awt.Shape;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.Color;
import java.util.List;
import java.util.Iterator;
import org.apache.batik.gvt.text.Mark;
import org.apache.batik.gvt.TextPainter;
import org.apache.batik.gvt.TextNode;
import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
import org.apache.batik.gvt.font.GVTFontFamily;
import org.apache.batik.bridge.SVGFontFamily;
import org.apache.batik.gvt.renderer.StrokingTextPainter;
import org.apache.fop.fonts.FontMetrics;
import org.apache.fop.layout.FontState;
import org.apache.fop.layout.FontInfo;
/**
* Renders the attributed character iterator of a <tt>TextNode</tt>.
* This class draws the text directly into the PSGraphics2D so that
* the text is not drawn using shapes which makes the PS files larger.
* If the text is simple enough to draw then it sets the font and calls
* drawString. If the text is complex or the cannot be translated
* into a simple drawString the StrokingTextPainter is used instead.
*
* @todo handle underline, overline and strikethrough
* @todo use drawString(AttributedCharacterIterator iterator...) for some
*
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
* @version $Id: PSTextPainter.java,v 1.15 2003/01/08 14:03:55 jeremias Exp $
*/
public class PSTextPainter implements TextPainter {
private FontInfo fontInfo;
/**
* Use the stroking text painter to get the bounds and shape.
* Also used as a fallback to draw the string with strokes.
*/
protected static final TextPainter PROXY_PAINTER =
StrokingTextPainter.getInstance();
/**
* Create a new PS text painter with the given font information.
* @param fi the fint info
*/
public PSTextPainter(FontInfo fi) {
fontInfo = fi;
}
/**
* Paints the specified attributed character iterator using the
* specified Graphics2D and context and font context.
* @param node the TextNode to paint
* @param g2d the Graphics2D to use
*/
public void paint(TextNode node, Graphics2D g2d) {
// System.out.println("PSText paint");
String txt = node.getText();
Point2D loc = node.getLocation();
AttributedCharacterIterator aci =
node.getAttributedCharacterIterator();
// reset position to start of char iterator
if (aci.getBeginIndex() == aci.getEndIndex()) {
return;
}
char ch = aci.first();
if (ch == AttributedCharacterIterator.DONE) {
return;
}
TextNode.Anchor anchor;
anchor = (TextNode.Anchor) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
List gvtFonts;
gvtFonts = (List) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
Paint forg = (Paint) aci.getAttribute(TextAttribute.FOREGROUND);
Paint strokePaint;
strokePaint = (Paint) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT);
Float size = (Float) aci.getAttribute(TextAttribute.SIZE);
if (size == null) {
return;
}
Stroke stroke = (Stroke) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.STROKE);
/*
Float xpos = (Float) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.X);
Float ypos = (Float) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.Y);
*/
Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
boolean useStrokePainter = false;
if (forg instanceof Color) {
Color col = (Color) forg;
if (col.getAlpha() != 255) {
useStrokePainter = true;
}
g2d.setColor(col);
}
g2d.setPaint(forg);
g2d.setStroke(stroke);
if (strokePaint != null) {
// need to draw using AttributedCharacterIterator
useStrokePainter = true;
}
if (hasUnsupportedAttributes(aci)) {
useStrokePainter = true;
}
// text contains unsupported information
if (useStrokePainter) {
PROXY_PAINTER.paint(node, g2d);
return;
}
String style = ((posture != null) && (posture.floatValue() > 0.0))
? "italic" : "normal";
int weight = ((taWeight != null)
&& (taWeight.floatValue() > 1.0)) ? FontInfo.BOLD
: FontInfo.NORMAL;
FontState fontState = null;
FontInfo fi = fontInfo;
boolean found = false;
String fontFamily = null;
if (gvtFonts != null) {
Iterator i = gvtFonts.iterator();
while (i.hasNext()) {
GVTFontFamily fam = (GVTFontFamily) i.next();
if (fam instanceof SVGFontFamily) {
PROXY_PAINTER.paint(node, g2d);
return;
}
fontFamily = fam.getFamilyName();
if (fi.hasFont(fontFamily, style, weight)) {
String fname = fontInfo.fontLookup(fontFamily, style,
weight);
FontMetrics metrics = fontInfo.getMetricsFor(fname);
int fsize = (int)(size.floatValue() * 1000);
fontState = new FontState(fname, metrics, fsize);
found = true;
break;
}
}
}
if (!found) {
String fname =
fontInfo.fontLookup("any", style, FontInfo.NORMAL);
FontMetrics metrics = fontInfo.getMetricsFor(fname);
int fsize = (int)(size.floatValue() * 1000);
fontState = new FontState(fname, metrics, fsize);
} else {
if (g2d instanceof PSGraphics2D) {
((PSGraphics2D) g2d).setOverrideFontState(fontState);
}
}
int fStyle = Font.PLAIN;
if (weight == FontInfo.BOLD) {
if (style.equals("italic")) {
fStyle = Font.BOLD | Font.ITALIC;
} else {
fStyle = Font.BOLD;
}
} else {
if (style.equals("italic")) {
fStyle = Font.ITALIC;
} else {
fStyle = Font.PLAIN;
}
}
Font font = new Font(fontFamily, fStyle,
(int)(fontState.getFontSize() / 1000));
g2d.setFont(font);
float advance = getStringWidth(txt, fontState);
float tx = 0;
if (anchor != null) {
switch (anchor.getType()) {
case TextNode.Anchor.ANCHOR_MIDDLE:
tx = -advance / 2;
break;
case TextNode.Anchor.ANCHOR_END:
tx = -advance;
}
}
g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
}
private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
boolean hasunsupported = false;
Object letSpace = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
if (letSpace != null) {
hasunsupported = true;
}
Object wordSpace = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
if (wordSpace != null) {
hasunsupported = true;
}
AttributedCharacterIterator.Attribute key;
key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE;
Object writeMod = aci.getAttribute(key);
if (!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
writeMod)) {
hasunsupported = true;
}
Object vertOr = aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
vertOr)) {
hasunsupported = true;
}
return hasunsupported;
}
private float getStringWidth(String str, FontState fontState) {
float wordWidth = 0;
float whitespaceWidth = fontState.getWidth(fontState.mapChar(' '));
for (int i = 0; i < str.length(); i++) {
float charWidth;
char c = str.charAt(i);
if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) {
charWidth = fontState.getWidth(fontState.mapChar(c));
if (charWidth <= 0) {
charWidth = whitespaceWidth;
}
} else {
charWidth = whitespaceWidth;
}
wordWidth += charWidth;
}
return wordWidth / 1000f;
}
/**
* Get the outline shape of the text characters.
* This uses the StrokingTextPainter to get the outline
* shape since in theory it should be the same.
*
* @param node the text node
* @return the outline shape of the text characters
*/
public Shape getOutline(TextNode node) {
return PROXY_PAINTER.getOutline(node);
}
/**
* Get the bounds.
* This uses the StrokingTextPainter to get the bounds
* since in theory it should be the same.
*
* @param node the text node
* @return the bounds of the text
*/
public Rectangle2D getBounds2D(TextNode node) {
return PROXY_PAINTER.getBounds2D(node);
}
/**
* Get the geometry bounds.
* This uses the StrokingTextPainter to get the bounds
* since in theory it should be the same.
* @param node the text node
* @return the bounds of the text
*/
public Rectangle2D getGeometryBounds(TextNode node) {
return PROXY_PAINTER.getGeometryBounds(node);
}
// Methods that have no purpose for PS
/**
* Get the mark.
* This does nothing since the output is pdf and not interactive.
* @param node the text node
* @param pos the position
* @param all select all
* @return null
*/
public Mark getMark(TextNode node, int pos, boolean all) {
System.out.println("PSText getMark");
return null;
}
/**
* Select at.
* This does nothing since the output is pdf and not interactive.
* @param x the x position
* @param y the y position
* @param node the text node
* @return null
*/
public Mark selectAt(double x, double y, TextNode node) {
System.out.println("PSText selectAt");
return null;
}
/**
* Select to.
* This does nothing since the output is pdf and not interactive.
* @param x the x position
* @param y the y position
* @param beginMark the start mark
* @return null
*/
public Mark selectTo(double x, double y, Mark beginMark) {
System.out.println("PSText selectTo");
return null;
}
/**
* Selec first.
* This does nothing since the output is pdf and not interactive.
* @param node the text node
* @return null
*/
public Mark selectFirst(TextNode node) {
System.out.println("PSText selectFirst");
return null;
}
/**
* Select last.
* This does nothing since the output is pdf and not interactive.
* @param node the text node
* @return null
*/
public Mark selectLast(TextNode node) {
System.out.println("PSText selectLast");
return null;
}
/**
* Get selected.
* This does nothing since the output is pdf and not interactive.
* @param start the start mark
* @param finish the finish mark
* @return null
*/
public int[] getSelected(Mark start, Mark finish) {
System.out.println("PSText getSelected");
return null;
}
/**
* Get the highlighted shape.
* This does nothing since the output is pdf and not interactive.
* @param beginMark the start mark
* @param endMark the end mark
* @return null
*/
public Shape getHighlightShape(Mark beginMark, Mark endMark) {
System.out.println("PSText getHighlightShape");
return null;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: fop-cvs-help@xml.apache.org