package org.apache.fop.render.java2d;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.Stack;
import org.w3c.dom.Document;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.intermediate.AbstractIFPainter;
import org.apache.fop.render.intermediate.BorderPainter;
import org.apache.fop.render.intermediate.GraphicsPainter;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.CharUtilities;
public class Java2DPainter extends AbstractIFPainter<IFDocumentHandler> {
protected IFContext ifContext;
protected FontInfo fontInfo;
private final GraphicsPainter graphicsPainter;
private final BorderPainter borderPainter;
protected Java2DGraphicsState g2dState;
private Stack<Java2DGraphicsState> g2dStateStack = new Stack<Java2DGraphicsState>();
public Java2DPainter(Graphics2D g2d, IFContext context, FontInfo fontInfo) {
this(g2d, context, fontInfo, new Java2DDocumentHandler());
}
public Java2DPainter(Graphics2D g2d, IFContext context, FontInfo fontInfo, IFDocumentHandler documentHandler) {
this(g2d, context, fontInfo, null, documentHandler);
}
public Java2DPainter(Graphics2D g2d, IFContext context, FontInfo fontInfo, IFState state) {
this(g2d, context, fontInfo, state, new Java2DDocumentHandler());
}
public Java2DPainter(Graphics2D g2d, IFContext context, FontInfo fontInfo, IFState state,
IFDocumentHandler documentHandler) {
super(documentHandler);
this.ifContext = context;
if (state != null) {
this.state = state.push();
} else {
this.state = IFState.create();
}
this.fontInfo = fontInfo;
this.g2dState = new Java2DGraphicsState(g2d, fontInfo, g2d.getTransform());
graphicsPainter = new Java2DGraphicsPainter(this);
this.borderPainter = new BorderPainter(graphicsPainter);
}
public IFContext getContext() {
return this.ifContext;
}
protected FontInfo getFontInfo() {
return this.fontInfo;
}
protected Java2DGraphicsState getState() {
return this.g2dState;
}
public void startViewport(AffineTransform transform, Dimension size, Rectangle clipRect)
throws IFException {
saveGraphicsState();
try {
concatenateTransformationMatrix(transform);
if (clipRect != null) {
clipRect(clipRect);
}
} catch (IOException ioe) {
throw new IFException("I/O error in startViewport()", ioe);
}
}
public void endViewport() throws IFException {
restoreGraphicsState();
}
public void startGroup(AffineTransform transform, String layer) throws IFException {
saveGraphicsState();
try {
concatenateTransformationMatrix(transform);
} catch (IOException ioe) {
throw new IFException("I/O error in startGroup()", ioe);
}
}
public void endGroup() throws IFException {
restoreGraphicsState();
}
public void drawImage(String uri, Rectangle rect) throws IFException {
drawImageUsingURI(uri, rect);
}
protected RenderingContext createRenderingContext() {
Java2DRenderingContext java2dContext = new Java2DRenderingContext(
getUserAgent(), g2dState.getGraph(), getFontInfo());
return java2dContext;
}
public void drawImage(Document doc, Rectangle rect) throws IFException {
drawImageUsingDocument(doc, rect);
}
public void clipRect(Rectangle rect) throws IFException {
getState().updateClip(rect);
}
public void clipBackground(Rectangle rect, BorderProps bpsBefore, BorderProps bpsAfter,
BorderProps bpsStart, BorderProps bpsEnd) throws IFException {
}
public void fillRect(Rectangle rect, Paint fill) throws IFException {
if (fill == null) {
return;
}
if (rect.width != 0 && rect.height != 0) {
g2dState.updatePaint(fill);
g2dState.getGraph().fill(rect);
}
}
public void drawBorderRect(Rectangle rect, BorderProps top, BorderProps bottom,
BorderProps left, BorderProps right) throws IFException {
if (top != null || bottom != null || left != null || right != null) {
this.borderPainter.drawBorders(rect, top, bottom, left, right, null);
}
}
public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
throws IFException {
try {
this.graphicsPainter.drawLine(start, end, width, color, style);
} catch (IOException ioe) {
throw new IFException("Unexpected error drawing line", ioe);
}
}
public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[][] dp, String text)
throws IFException {
g2dState.updateColor(state.getTextColor());
FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
Font font = getFontInfo().getFontInstance(triplet, state.getFontSize());
g2dState.updateFont(font.getFontName(), state.getFontSize() * 1000);
Graphics2D g2d = this.g2dState.getGraph();
GlyphVector gv = Java2DUtil.createGlyphVector(text, g2d, font, fontInfo);
Point2D cursor = new Point2D.Float(0, 0);
int l = text.length();
if (dp != null && dp[0] != null && (dp[0][0] != 0 || dp[0][1] != 0)) {
cursor.setLocation(cursor.getX() + dp[0][0], cursor.getY() - dp[0][1]);
gv.setGlyphPosition(0, cursor);
}
int currentIdx = 0;
for (int i = 0; i < l; i++) {
int orgChar = text.codePointAt(i);
i += CharUtilities.incrementIfNonBMP(orgChar);
float xGlyphAdjust = 0;
float yGlyphAdjust = 0;
int cw = font.getCharWidth(orgChar);
if ((wordSpacing != 0) && CharUtilities.isAdjustableSpace(orgChar)) {
xGlyphAdjust += wordSpacing;
}
xGlyphAdjust += letterSpacing;
if (dp != null && i < dp.length && dp[i] != null) {
xGlyphAdjust += dp[i][2] - dp[i][0];
yGlyphAdjust += dp[i][3] - dp[i][1];
}
if (dp != null && i < dp.length - 1 && dp[i + 1] != null) {
xGlyphAdjust += dp[i + 1][0];
yGlyphAdjust += dp[i + 1][1];
}
cursor.setLocation(cursor.getX() + cw + xGlyphAdjust, cursor.getY() - yGlyphAdjust);
gv.setGlyphPosition(++currentIdx, cursor);
}
g2d.drawGlyphVector(gv, x, y);
}
protected void saveGraphicsState() {
g2dStateStack.push(g2dState);
g2dState = new Java2DGraphicsState(g2dState);
}
protected void restoreGraphicsState() {
g2dState.dispose();
g2dState = g2dStateStack.pop();
}
private void concatenateTransformationMatrix(AffineTransform transform) throws IOException {
g2dState.transform(transform);
}
}