2004-05-15 00:17:44 +02:00
|
|
|
/* Copyright (C) 2000, 2003, 2004 Free Software Foundation
|
2000-10-22 19:46:09 +02:00
|
|
|
|
|
|
|
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;
|
2003-08-25 21:02:29 +02:00
|
|
|
import gnu.gcj.xlib.Pixmap;
|
2000-10-22 19:46:09 +02:00
|
|
|
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()
|
|
|
|
{
|
2003-07-21 04:24:09 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
XGraphics gfxCopy = (XGraphics) super.clone();
|
|
|
|
gfxCopy.context = context.create();
|
|
|
|
|
|
|
|
return gfxCopy;
|
|
|
|
}
|
|
|
|
catch (CloneNotSupportedException ex)
|
|
|
|
{
|
|
|
|
// This should never happen.
|
|
|
|
throw new InternalError ();
|
|
|
|
}
|
2000-10-22 19:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void dispose()
|
|
|
|
{
|
|
|
|
GC lContext = context;
|
|
|
|
context = null;
|
|
|
|
config = null;
|
|
|
|
clipBounds = null;
|
2003-04-19 21:54:39 +02:00
|
|
|
metrics = null;
|
2000-10-22 19:46:09 +02:00
|
|
|
|
|
|
|
if (lContext != null)
|
2003-04-19 21:54:39 +02:00
|
|
|
{
|
|
|
|
lContext.dispose();
|
|
|
|
}
|
2000-10-22 19:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public XGraphics(Drawable drawable, XGraphicsConfiguration config)
|
|
|
|
{
|
2003-04-19 21:54:39 +02:00
|
|
|
context = GC.create(drawable);
|
2000-10-22 19:46:09 +02:00
|
|
|
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)
|
|
|
|
{
|
2004-01-29 20:28:26 +01:00
|
|
|
if (font == null)
|
|
|
|
return;
|
|
|
|
if ((metrics != null) && font.equals(metrics.getFont()))
|
|
|
|
return;
|
2000-10-22 19:46:09 +02:00
|
|
|
metrics = config.getXFontMetrics(font);
|
2004-01-29 20:28:26 +01:00
|
|
|
if (metrics != null)
|
|
|
|
context.setFont(metrics.xfont);
|
2000-10-22 19:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2004-01-29 20:28:26 +01:00
|
|
|
/* FIXME: decide whether this test code is worth anything
|
|
|
|
* (as of 2004-01-29, it prints frequently)
|
2000-10-22 19:46:09 +02:00
|
|
|
if ((clipBounds != null) && !clipBounds.contains(newClipBounds))
|
|
|
|
{
|
|
|
|
System.err.println("warning: old clip ("+ clipBounds +") does " +
|
|
|
|
"not fully contain new clip (" +
|
|
|
|
newClipBounds + ")");
|
|
|
|
}
|
2004-01-29 20:28:26 +01:00
|
|
|
*/
|
2000-10-22 19:46:09 +02:00
|
|
|
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)
|
|
|
|
{
|
2003-06-12 05:08:58 +02:00
|
|
|
context.drawArc (x, y, width, height, startAngle, arcAngle);
|
2000-10-22 19:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void fillArc(int x, int y, int width, int height, int
|
|
|
|
startAngle, int arcAngle)
|
|
|
|
{
|
2003-06-12 05:08:58 +02:00
|
|
|
context.fillArc (x, y, width, height, startAngle, arcAngle);
|
2000-10-22 19:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2003-01-16 00:53:49 +01:00
|
|
|
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints,
|
|
|
|
int translateX, int translateY)
|
2000-10-22 19:46:09 +02:00
|
|
|
{
|
2003-01-16 00:53:49 +01:00
|
|
|
context.fillPolygon(xPoints, yPoints, nPoints, translateX, translateY);
|
2000-10-22 19:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2003-08-25 21:02:29 +02:00
|
|
|
if (img instanceof XOffScreenImage)
|
|
|
|
{
|
|
|
|
// FIXME: have to enforce clip, or is it OK as-is?
|
2004-05-15 00:17:44 +02:00
|
|
|
XOffScreenImage offScreenImage = (XOffScreenImage) img;
|
2003-08-25 21:02:29 +02:00
|
|
|
Pixmap pixmap = offScreenImage.getPixmap ();
|
|
|
|
context.copyArea (pixmap, 0, 0, x, y,
|
|
|
|
offScreenImage.getWidth (), offScreenImage.getHeight ());
|
|
|
|
return true;
|
|
|
|
}
|
2000-10-22 19:46:09 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|