| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.afp; |
| |
| import java.awt.AlphaComposite; |
| import java.awt.BasicStroke; |
| import java.awt.Color; |
| import java.awt.Dimension; |
| import java.awt.Font; |
| import java.awt.FontMetrics; |
| import java.awt.Graphics; |
| import java.awt.GraphicsConfiguration; |
| import java.awt.Image; |
| import java.awt.Paint; |
| import java.awt.Rectangle; |
| import java.awt.Shape; |
| import java.awt.Stroke; |
| import java.awt.geom.AffineTransform; |
| import java.awt.geom.Ellipse2D; |
| import java.awt.geom.Line2D; |
| import java.awt.geom.PathIterator; |
| import java.awt.geom.Rectangle2D; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.ImageObserver; |
| import java.awt.image.RenderedImage; |
| import java.awt.image.renderable.RenderableImage; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.xmlgraphics.image.loader.ImageInfo; |
| import org.apache.xmlgraphics.image.loader.ImageSize; |
| import org.apache.xmlgraphics.image.loader.impl.ImageRendered; |
| import org.apache.xmlgraphics.java2d.AbstractGraphics2D; |
| import org.apache.xmlgraphics.java2d.GraphicContext; |
| import org.apache.xmlgraphics.java2d.GraphicsConfigurationWithTransparency; |
| import org.apache.xmlgraphics.java2d.StrokingTextHandler; |
| import org.apache.xmlgraphics.java2d.TextHandler; |
| import org.apache.xmlgraphics.util.UnitConv; |
| |
| import org.apache.fop.afp.goca.GraphicsSetLineType; |
| import org.apache.fop.afp.modca.GraphicsObject; |
| import org.apache.fop.afp.modca.ResourceObject; |
| import org.apache.fop.afp.util.CubicBezierApproximator; |
| import org.apache.fop.fonts.FontInfo; |
| import org.apache.fop.render.afp.AFPImageHandlerRenderedImage; |
| import org.apache.fop.render.afp.AFPRenderingContext; |
| import org.apache.fop.svg.NativeImageHandler; |
| |
| /** |
| * This is a concrete implementation of {@link AbstractGraphics2D} (and |
| * therefore of {@link java.awt.Graphics2D}) which is able to generate GOCA byte |
| * codes. |
| * |
| * @see org.apache.xmlgraphics.java2d.AbstractGraphics2D |
| */ |
| public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHandler { |
| |
| private static final Log LOG = LogFactory.getLog(AFPGraphics2D.class); |
| |
| private static final int X = 0; |
| |
| private static final int Y = 1; |
| |
| private static final int X1 = 0; |
| |
| private static final int Y1 = 1; |
| |
| private static final int X2 = 2; |
| |
| private static final int Y2 = 3; |
| |
| private static final int X3 = 4; |
| |
| private static final int Y3 = 5; |
| |
| /** graphics object */ |
| private GraphicsObject graphicsObj; |
| |
| /** Fallback text handler */ |
| protected TextHandler fallbackTextHandler = new StrokingTextHandler(); |
| |
| /** Custom text handler */ |
| protected TextHandler customTextHandler; |
| |
| /** AFP resource manager */ |
| private AFPResourceManager resourceManager; |
| |
| /** AFP resource info */ |
| private AFPResourceInfo resourceInfo; |
| |
| /** Current AFP state */ |
| private AFPPaintingState paintingState; |
| |
| /** AFP graphics configuration */ |
| private final GraphicsConfigurationWithTransparency graphicsConfig = new GraphicsConfigurationWithTransparency(); |
| |
| /** The AFP FontInfo */ |
| private FontInfo fontInfo; |
| |
| /** |
| * Main constructor |
| * |
| * @param textAsShapes |
| * if true, all text is turned into shapes in the convertion. No |
| * text is output. |
| * @param paintingState painting state |
| * @param resourceManager resource manager |
| * @param resourceInfo resource info |
| * @param fontInfo font info |
| */ |
| public AFPGraphics2D(boolean textAsShapes, AFPPaintingState paintingState, |
| AFPResourceManager resourceManager, AFPResourceInfo resourceInfo, |
| FontInfo fontInfo) { |
| super(textAsShapes); |
| setPaintingState(paintingState); |
| setResourceManager(resourceManager); |
| setResourceInfo(resourceInfo); |
| setFontInfo(fontInfo); |
| } |
| |
| /** |
| * Copy Constructor |
| * |
| * @param g2d |
| * a AFPGraphics2D whose properties should be copied |
| */ |
| public AFPGraphics2D(AFPGraphics2D g2d) { |
| super(g2d); |
| this.paintingState = g2d.paintingState; |
| this.resourceManager = g2d.resourceManager; |
| this.resourceInfo = g2d.resourceInfo; |
| this.fontInfo = g2d.fontInfo; |
| |
| this.graphicsObj = g2d.graphicsObj; |
| this.fallbackTextHandler = g2d.fallbackTextHandler; |
| this.customTextHandler = g2d.customTextHandler; |
| } |
| |
| /** |
| * Sets the AFP resource manager |
| * |
| * @param resourceManager the AFP resource manager |
| */ |
| private void setResourceManager(AFPResourceManager resourceManager) { |
| this.resourceManager = resourceManager; |
| } |
| |
| /** |
| * Returns the AFP resource manager associated with this {@link java.awt.Graphics2D} instance. |
| * @return the resource manager |
| */ |
| public AFPResourceManager getResourceManager() { |
| return this.resourceManager; |
| } |
| |
| /** |
| * Sets the AFP resource info |
| * |
| * @param resourceInfo the AFP resource info |
| */ |
| private void setResourceInfo(AFPResourceInfo resourceInfo) { |
| this.resourceInfo = resourceInfo; |
| } |
| |
| /** |
| * Returns the GOCA graphics object |
| * |
| * @return the GOCA graphics object |
| */ |
| public GraphicsObject getGraphicsObject() { |
| return this.graphicsObj; |
| } |
| |
| /** |
| * Sets the GOCA graphics object |
| * |
| * @param obj the GOCA graphics object |
| */ |
| public void setGraphicsObject(GraphicsObject obj) { |
| this.graphicsObj = obj; |
| } |
| |
| /** |
| * Sets the AFP painting state |
| * |
| * @param paintingState the AFP painting state |
| */ |
| private void setPaintingState(AFPPaintingState paintingState) { |
| this.paintingState = paintingState; |
| } |
| |
| /** |
| * Returns the AFP painting state |
| * |
| * @return the AFP painting state |
| */ |
| public AFPPaintingState getPaintingState() { |
| return this.paintingState; |
| } |
| |
| /** |
| * Sets the FontInfo |
| * |
| * @param fontInfo the FontInfo |
| */ |
| private void setFontInfo(FontInfo fontInfo) { |
| this.fontInfo = fontInfo; |
| } |
| |
| /** |
| * Returns the FontInfo |
| * |
| * @return the FontInfo |
| */ |
| public FontInfo getFontInfo() { |
| return this.fontInfo; |
| } |
| |
| /** |
| * Sets the GraphicContext |
| * |
| * @param gc |
| * GraphicContext to use |
| */ |
| public void setGraphicContext(GraphicContext gc) { |
| this.gc = gc; |
| } |
| |
| private int getResolution() { |
| return this.paintingState.getResolution(); |
| } |
| |
| /** |
| * Converts a length value to an absolute value. |
| * Please note that this only uses the "ScaleY" factor, so this will result |
| * in a bad value should "ScaleX" and "ScaleY" be different. |
| * @param length the length |
| * @return the absolute length |
| */ |
| public double convertToAbsoluteLength(double length) { |
| AffineTransform current = getTransform(); |
| double mult = getResolution() / (double)UnitConv.IN2PT; |
| double factor = -current.getScaleY() / mult; |
| return length * factor; |
| } |
| |
| /** |
| * Apply the stroke to the AFP graphics object. |
| * This takes the java stroke and outputs the appropriate settings |
| * to the AFP graphics object so that the stroke attributes are handled. |
| * |
| * @param stroke the java stroke |
| */ |
| protected void applyStroke(Stroke stroke) { |
| if (stroke instanceof BasicStroke) { |
| BasicStroke basicStroke = (BasicStroke) stroke; |
| |
| // set line width and correct it; NOTE: apparently we need to correct the width so that the |
| // output looks OK since the default with depends on the output device |
| float lineWidth = basicStroke.getLineWidth(); |
| float correction = paintingState.getLineWidthCorrection(); |
| graphicsObj.setLineWidth(lineWidth * correction); |
| |
| //No line join, miter limit and end cap support in GOCA. :-( |
| |
| // set line type/style (note: this is an approximation at best!) |
| float[] dashArray = basicStroke.getDashArray(); |
| if (paintingState.setDashArray(dashArray)) { |
| byte type = GraphicsSetLineType.DEFAULT; // normally SOLID |
| if (dashArray != null) { |
| type = GraphicsSetLineType.DOTTED; // default to plain DOTTED if dashed line |
| // float offset = basicStroke.getDashPhase(); |
| if (dashArray.length == 2) { |
| if (dashArray[0] < dashArray[1]) { |
| type = GraphicsSetLineType.SHORT_DASHED; |
| } else if (dashArray[0] > dashArray[1]) { |
| type = GraphicsSetLineType.LONG_DASHED; |
| } |
| } else if (dashArray.length == 4) { |
| if (dashArray[0] > dashArray[1] |
| && dashArray[2] < dashArray[3]) { |
| type = GraphicsSetLineType.DASH_DOT; |
| } else if (dashArray[0] < dashArray[1] |
| && dashArray[2] < dashArray[3]) { |
| type = GraphicsSetLineType.DOUBLE_DOTTED; |
| } |
| } else if (dashArray.length == 6) { |
| if (dashArray[0] > dashArray[1] |
| && dashArray[2] < dashArray[3] |
| && dashArray[4] < dashArray[5]) { |
| type = GraphicsSetLineType.DASH_DOUBLE_DOTTED; |
| } |
| } |
| } |
| graphicsObj.setLineType(type); |
| } |
| } else { |
| LOG.warn("Unsupported Stroke: " + stroke.getClass().getName()); |
| } |
| } |
| |
| /** |
| * Apply the java paint to the AFP. |
| * This takes the java paint sets up the appropriate AFP commands |
| * for the drawing with that paint. |
| * Currently this supports the gradients and patterns from batik. |
| * |
| * @param paint the paint to convert to AFP |
| * @param fill true if the paint should be set for filling |
| * @return true if the paint is handled natively, false if the paint should be rasterized |
| */ |
| private boolean applyPaint(Paint paint, boolean fill) { |
| if (paint instanceof Color) { |
| return true; |
| } |
| LOG.debug("NYI: applyPaint() " + paint + " fill=" + fill); |
| // if (paint instanceof TexturePaint) { |
| // TexturePaint texturePaint = (TexturePaint)paint; |
| // BufferedImage bufferedImage = texturePaint.getImage(); |
| // AffineTransform at = paintingState.getTransform(); |
| // int x = (int)Math.round(at.getTranslateX()); |
| // int y = (int)Math.round(at.getTranslateY()); |
| // drawImage(bufferedImage, x, y, null); |
| // } |
| return false; |
| } |
| |
| |
| /** |
| * Handle the Batik drawing event |
| * |
| * @param shape |
| * the shape to draw |
| * @param fill |
| * true if the shape is to be drawn filled |
| */ |
| private void doDrawing(Shape shape, boolean fill) { |
| if (!fill) { |
| graphicsObj.newSegment(); |
| } |
| |
| graphicsObj.setColor(gc.getColor()); |
| |
| applyPaint(gc.getPaint(), fill); |
| |
| if (fill) { |
| graphicsObj.beginArea(); |
| } else { |
| applyStroke(gc.getStroke()); |
| } |
| |
| AffineTransform trans = gc.getTransform(); |
| PathIterator iter = shape.getPathIterator(trans); |
| if (shape instanceof Line2D) { |
| double[] dstPts = new double[6]; |
| iter.currentSegment(dstPts); |
| int[] coords = new int[4]; |
| coords[X1] = (int) Math.round(dstPts[X]); |
| coords[Y1] = (int) Math.round(dstPts[Y]); |
| iter.next(); |
| iter.currentSegment(dstPts); |
| coords[X2] = (int) Math.round(dstPts[X]); |
| coords[Y2] = (int) Math.round(dstPts[Y]); |
| graphicsObj.addLine(coords); |
| } else if (shape instanceof Rectangle2D) { |
| double[] dstPts = new double[6]; |
| iter.currentSegment(dstPts); |
| int[] coords = new int[4]; |
| coords[X2] = (int) Math.round(dstPts[X]); |
| coords[Y2] = (int) Math.round(dstPts[Y]); |
| iter.next(); |
| iter.next(); |
| iter.currentSegment(dstPts); |
| coords[X1] = (int) Math.round(dstPts[X]); |
| coords[Y1] = (int) Math.round(dstPts[Y]); |
| graphicsObj.addBox(coords); |
| } else if (shape instanceof Ellipse2D) { |
| double[] dstPts = new double[6]; |
| Ellipse2D elip = (Ellipse2D) shape; |
| double scale = trans.getScaleX(); |
| double radiusWidth = elip.getWidth() / 2; |
| double radiusHeight = elip.getHeight() / 2; |
| graphicsObj.setArcParams( |
| (int)Math.round(radiusWidth * scale), |
| (int)Math.round(radiusHeight * scale), |
| 0, |
| 0 |
| ); |
| double[] srcPts = new double[] {elip.getCenterX(), elip.getCenterY()}; |
| trans.transform(srcPts, 0, dstPts, 0, 1); |
| final int mh = 1; |
| final int mhr = 0; |
| graphicsObj.addFullArc( |
| (int)Math.round(dstPts[X]), |
| (int)Math.round(dstPts[Y]), |
| mh, |
| mhr |
| ); |
| } else { |
| processPathIterator(iter); |
| } |
| |
| if (fill) { |
| graphicsObj.endArea(); |
| } |
| } |
| |
| /** |
| * Processes a path iterator generating the necessary painting operations. |
| * |
| * @param iter PathIterator to process |
| */ |
| private void processPathIterator(PathIterator iter) { |
| double[] dstPts = new double[6]; |
| double[] currentPosition = new double[2]; |
| List<Integer> fillets = new ArrayList<Integer>(); |
| for (int[] openingCoords = new int[2]; !iter.isDone(); iter.next()) { |
| switch (iter.currentSegment(dstPts)) { |
| case PathIterator.SEG_LINETO: |
| flush(fillets); |
| graphicsObj.addLine(new int[] { |
| (int)Math.round(dstPts[X]), |
| (int)Math.round(dstPts[Y]) |
| }, true); |
| currentPosition = new double[]{dstPts[X], dstPts[Y]}; |
| break; |
| case PathIterator.SEG_QUADTO: |
| flush(fillets); |
| graphicsObj.addFillet(new int[] { |
| (int)Math.round(dstPts[X1]), |
| (int)Math.round(dstPts[Y1]), |
| (int)Math.round(dstPts[X2]), |
| (int)Math.round(dstPts[Y2]) |
| }, true); |
| currentPosition = new double[]{dstPts[X2], dstPts[Y2]}; |
| break; |
| case PathIterator.SEG_CUBICTO: |
| double[] cubicCoords = new double[] {currentPosition[0], currentPosition[1], |
| dstPts[X1], dstPts[Y1], dstPts[X2], dstPts[Y2], dstPts[X3], dstPts[Y3]}; |
| double[][] quadParts = CubicBezierApproximator.fixedMidPointApproximation( |
| cubicCoords); |
| if (quadParts.length >= 4) { |
| for (double[] quadPts : quadParts) { |
| if (quadPts != null && quadPts.length == 4) { |
| fillets.add((int) Math.round(quadPts[X1])); |
| fillets.add((int) Math.round(quadPts[Y1])); |
| fillets.add((int) Math.round(quadPts[X2])); |
| fillets.add((int) Math.round(quadPts[Y2])); |
| currentPosition = new double[]{quadPts[X2], quadPts[Y2]}; |
| } |
| } |
| } |
| break; |
| case PathIterator.SEG_MOVETO: |
| flush(fillets); |
| openingCoords = new int[] { |
| (int)Math.round(dstPts[X]), |
| (int)Math.round(dstPts[Y]) |
| }; |
| currentPosition = new double[]{dstPts[X], dstPts[Y]}; |
| graphicsObj.setCurrentPosition(openingCoords); |
| break; |
| case PathIterator.SEG_CLOSE: |
| flush(fillets); |
| graphicsObj.addLine(openingCoords, true); |
| currentPosition = new double[]{openingCoords[0], openingCoords[1]}; |
| break; |
| default: |
| LOG.debug("Unrecognised path iterator type"); |
| break; |
| } |
| } |
| flush(fillets); |
| } |
| |
| private void flush(List<Integer> fillets) { |
| List<int[]> intList = listToIntLists(fillets); |
| for (int[] ints : intList) { |
| graphicsObj.addFillet(ints, true); |
| } |
| } |
| |
| private List<int[]> listToIntLists(List<Integer> input) { |
| List<int[]> out = new ArrayList<int[]>(); |
| while (!input.isEmpty()) { |
| int[] data = new int[Math.min(100, input.size())]; |
| for (int i = 0; i < data.length; i++) { |
| data[i] = input.remove(0); |
| } |
| out.add(data); |
| } |
| return out; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void draw(Shape shape) { |
| LOG.debug("draw() shape=" + shape); |
| doDrawing(shape, false); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void fill(Shape shape) { |
| LOG.debug("fill() shape=" + shape); |
| doDrawing(shape, true); |
| } |
| |
| /** |
| * Central handler for IOExceptions for this class. |
| * |
| * @param ioe |
| * IOException to handle |
| */ |
| public void handleIOException(IOException ioe) { |
| // TODO Surely, there's a better way to do this. |
| LOG.error(ioe.getMessage()); |
| ioe.printStackTrace(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void drawString(String str, float x, float y) { |
| try { |
| if (customTextHandler != null && !textAsShapes) { |
| customTextHandler.drawString(this, str, x, y); |
| } else { |
| fallbackTextHandler.drawString(this, str, x, y); |
| } |
| } catch (IOException ioe) { |
| handleIOException(ioe); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public GraphicsConfiguration getDeviceConfiguration() { |
| return graphicsConfig; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Graphics create() { |
| return new AFPGraphics2D(this); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void dispose() { |
| this.graphicsObj = null; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public boolean drawImage(Image img, int x, int y, ImageObserver observer) { |
| return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); |
| } |
| |
| private BufferedImage buildBufferedImage(Dimension size) { |
| return new BufferedImage(size.width, size.height, |
| BufferedImage.TYPE_INT_ARGB); |
| } |
| |
| /** |
| * Draws an AWT image into a BufferedImage using an AWT Graphics2D implementation |
| * |
| * @param img the AWT image |
| * @param bufferedImage the AWT buffered image |
| * @param width the image width |
| * @param height the image height |
| * @param observer the image observer |
| * @return true if the image was drawn |
| */ |
| private boolean drawBufferedImage(Image img, BufferedImage bufferedImage, |
| int width, int height, ImageObserver observer) { |
| |
| java.awt.Graphics2D g2d = bufferedImage.createGraphics(); |
| try { |
| g2d.setComposite(AlphaComposite.SrcOver); |
| |
| Color color = new Color(1, 1, 1, 0); |
| g2d.setBackground(color); |
| g2d.setPaint(color); |
| |
| g2d.fillRect(0, 0, width, height); |
| |
| int imageWidth = bufferedImage.getWidth(); |
| int imageHeight = bufferedImage.getHeight(); |
| Rectangle clipRect = new Rectangle(0, 0, imageWidth, imageHeight); |
| g2d.clip(clipRect); |
| |
| g2d.setComposite(gc.getComposite()); |
| |
| return g2d.drawImage(img, 0, 0, imageWidth, imageHeight, observer); |
| } finally { |
| g2d.dispose(); //drawn so dispose immediately to free system resource |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public boolean drawImage(Image img, int x, int y, int width, int height, |
| ImageObserver observer) { |
| // draw with AWT Graphics2D |
| Dimension imageSize = new Dimension(width, height); |
| BufferedImage bufferedImage = buildBufferedImage(imageSize); |
| |
| boolean drawn = drawBufferedImage(img, bufferedImage, width, height, observer); |
| if (drawn) { |
| drawRenderedImage(bufferedImage, new AffineTransform()); |
| } |
| return false; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void drawRenderedImage(RenderedImage img, AffineTransform xform) { |
| int imgWidth = img.getWidth(); |
| int imgHeight = img.getHeight(); |
| |
| AffineTransform gat = gc.getTransform(); |
| int graphicsObjectHeight |
| = graphicsObj.getObjectEnvironmentGroup().getObjectAreaDescriptor().getHeight(); |
| |
| double toMillipointFactor = UnitConv.IN2PT * 1000 / (double)paintingState.getResolution(); |
| double x = gat.getTranslateX(); |
| double y = -(gat.getTranslateY() - graphicsObjectHeight); |
| x = toMillipointFactor * x; |
| y = toMillipointFactor * y; |
| double w = toMillipointFactor * imgWidth * gat.getScaleX(); |
| double h = toMillipointFactor * imgHeight * -gat.getScaleY(); |
| |
| AFPImageHandlerRenderedImage handler = new AFPImageHandlerRenderedImage(); |
| String uri = null; |
| if (resourceManager.getResourceLevelDefaults() |
| .getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC).isPrintFile()) { |
| uri = resourceInfo.getUri(); |
| } |
| ImageInfo imageInfo = new ImageInfo(uri, null); |
| imageInfo.setSize(new ImageSize( |
| img.getWidth(), img.getHeight(), paintingState.getResolution())); |
| imageInfo.getSize().calcSizeFromPixels(); |
| ImageRendered red = new ImageRendered(imageInfo, img, null); |
| Rectangle targetPos = new Rectangle( |
| (int)Math.round(x), |
| (int)Math.round(y), |
| (int)Math.round(w), |
| (int)Math.round(h)); |
| AFPRenderingContext context = new AFPRenderingContext(null, |
| resourceManager, paintingState, fontInfo, null); |
| resourceManager.includeCached = false; |
| try { |
| handler.handleImage(context, red, targetPos); |
| } catch (IOException ioe) { |
| handleIOException(ioe); |
| } |
| resourceManager.includeCached = true; |
| } |
| |
| /** |
| * Sets a custom TextHandler implementation that is responsible for painting |
| * text. The default TextHandler paints all text as shapes. A custom |
| * implementation can implement text painting using text painting operators. |
| * |
| * @param handler |
| * the custom TextHandler implementation |
| */ |
| public void setCustomTextHandler(TextHandler handler) { |
| this.customTextHandler = handler; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void drawRenderableImage(RenderableImage img, AffineTransform xform) { |
| LOG.debug("drawRenderableImage() NYI: img=" + img + ", xform=" + xform); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public FontMetrics getFontMetrics(Font f) { |
| LOG.debug("getFontMetrics() NYI: f=" + f); |
| return null; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void setXORMode(Color col) { |
| LOG.debug("setXORMode() NYI: col=" + col); |
| } |
| |
| /** {@inheritDoc} */ |
| public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, |
| float x, float y, float width, float height) { |
| LOG.debug("NYI: addNativeImage() " + "image=" + image |
| + ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void copyArea(int x, int y, int width, int height, int dx, int dy) { |
| LOG.debug("copyArea() NYI: "); |
| } |
| |
| public void clearRect(int x, int y, int width, int height) { |
| } |
| } |