/* Copyright (C) 2000 Free Software Foundation This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package gnu.awt.xlib; import java.awt.*; import java.awt.image.WritableRaster; import java.awt.image.Raster; import java.awt.image.DataBuffer; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; import java.awt.image.BufferedImage; import gnu.gcj.xlib.GC; import gnu.gcj.xlib.XImage; import gnu.gcj.xlib.Drawable; import gnu.gcj.xlib.Window; import gnu.gcj.xlib.Drawable; import gnu.gcj.xlib.Visual; import gnu.awt.j2d.DirectRasterGraphics; import gnu.awt.j2d.MappedRaster; public class XGraphics implements Cloneable, DirectRasterGraphics { static class XRaster extends MappedRaster { XImage ximage; public XRaster(WritableRaster raster, XImage ximage, ColorModel cm) { super(raster, cm); this.ximage = ximage; } } GC context; XGraphicsConfiguration config; Rectangle clipBounds; XFontMetrics metrics; public Object clone() { XGraphics gfxCopy = (XGraphics) super.clone(); gfxCopy.context = context.create(); return gfxCopy; } public void dispose() { GC lContext = context; context = null; config = null; clipBounds = null; if (lContext != null) { lContext.dispose(); } } public XGraphics(Drawable drawable, XGraphicsConfiguration config) { context = new GC(drawable); this.config = config; } public void setColor(Color color) { context.setForeground(config.getPixel(color)); } public void setPaintMode() { throw new UnsupportedOperationException("not implemented"); } public void setXORMode(Color c1) { throw new UnsupportedOperationException("not implemented"); } public void setFont(Font font) { if ((metrics != null) && font.equals(metrics.getFont())) return; metrics = config.getXFontMetrics(font); context.setFont(metrics.xfont); } public FontMetrics getFontMetrics(Font font) { if ((metrics != null) && font.equals(metrics.getFont())) return metrics; return config.getXFontMetrics(font); } public void setClip(int x, int y, int width, int height) { Rectangle[] rects = { new Rectangle(x, y, width, height) }; context.setClipRectangles(rects); } public void setClip(Shape clip) { /* TODO: create a special RectangleUnion shape that can be used to draw advantage of the GCs ability to set multiple rectangles. */ /* FIXME: creating all these objects is wasteful and can be costly in the long run, since this code is run at every expose. */ Rectangle newClipBounds = clip.getBounds(); if ((clipBounds != null) && !clipBounds.contains(newClipBounds)) { System.err.println("warning: old clip ("+ clipBounds +") does " + "not fully contain new clip (" + newClipBounds + ")"); } clipBounds = newClipBounds; Rectangle[] rects = { clipBounds }; context.setClipRectangles(rects); } public void copyArea(int x, int y, int width, int height, int dx, int dy) { throw new UnsupportedOperationException("not implemented"); } public void drawLine(int x1, int y1, int x2, int y2) { context.drawLine(x1, y1, x2, y2); } public void drawRect(int x, int y, int width, int height) { throw new UnsupportedOperationException("not implemented yet"); } public void fillRect(int x, int y, int width, int height) { context.fillRectangle(x, y, width, height); } public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { throw new UnsupportedOperationException("not implemented"); } public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { throw new UnsupportedOperationException("not implemented"); } public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { throw new UnsupportedOperationException("not implemented"); } public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { throw new UnsupportedOperationException("not implemented"); } public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { throw new UnsupportedOperationException("not implemented"); } public void drawString(String str, int x, int y) { context.drawString(str, x, y); } public boolean drawImage(Image img, int x, int y, ImageObserver observer) { if (clipBounds == null) return false; // ***FIXME*** if (!(img instanceof BufferedImage)) { throw new AWTError("unknown image class"); } BufferedImage bimg = (BufferedImage) img; XImage ximg = (XImage) bimg.getProperty("gnu.gcj.xlib.XImage"); if (ximg == null) { System.err.println("FIXME: skipping null XImage, should " + "really do on the spot conversion"); return false; } /* +------------------ | clip | +---------+ | img | | | +--+-------+ | | | | | | | | | | | | | +-------+-+ | | | | +----------+ */ int iLeft = Math.max(x, clipBounds.x); int iTop = Math.max(y, clipBounds.y); int iRight = Math.min(x + bimg.getWidth(), clipBounds.x + clipBounds.width); int iBottom = Math.min(y + bimg.getHeight(), clipBounds.y + clipBounds.height); int srcX = iLeft - x; int srcY = iTop - y; int width = iRight - iLeft; int height = iBottom - iTop; if ((width > 0) && (height > 0)) context.putImage(ximg, srcX, srcY, iLeft, iTop, width, height); return true; } public MappedRaster mapRaster(Rectangle bounds) { Visual visual = config.getVisual(); XImage ximage = new XImage(visual, bounds.width, bounds.height, false // do not auto allocate memory ); WritableRaster raster = config.createRasterForXImage(ximage, new Point(bounds.x, bounds.y)); DataBuffer dataB = raster.getDataBuffer(); XGraphicsConfiguration.attachData(ximage, dataB, 0); Drawable drawable = context.getDrawable(); // TODO: restrict to clipping Rectangle mBounds = drawable.copyIntoXImage(ximage, bounds, 0, 0); return new XRaster(raster, ximage, config.imageCM); } public void unmapRaster(MappedRaster mappedRaster) { XRaster xraster = (XRaster) mappedRaster; XImage ximage = xraster.ximage; Raster raster = xraster.getRaster(); int x = raster.getMinX(); int y = raster.getMinY(); int width = raster.getWidth(); int height = raster.getHeight(); context.putImage(ximage, 0, 0, x, y, width, height); } }