blob: 27b07a2369a631481171cf88ef8d7292c2078b92 [file] [log] [blame]
/* 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);
}
}