1 /* Copyright (C) 2000, 2003, 2004  Free Software Foundation
2 
3    This file is part of libgcj.
4 
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8 
9 package gnu.awt.xlib;
10 
11 import java.awt.*;
12 import java.awt.image.WritableRaster;
13 import java.awt.image.Raster;
14 import java.awt.image.DataBuffer;
15 import java.awt.image.ColorModel;
16 import java.awt.image.ImageObserver;
17 import java.awt.image.BufferedImage;
18 import gnu.gcj.xlib.GC;
19 import gnu.gcj.xlib.XImage;
20 import gnu.gcj.xlib.Drawable;
21 import gnu.gcj.xlib.Window;
22 import gnu.gcj.xlib.Drawable;
23 import gnu.gcj.xlib.Pixmap;
24 import gnu.gcj.xlib.Visual;
25 import gnu.awt.j2d.DirectRasterGraphics;
26 import gnu.awt.j2d.MappedRaster;
27 
28 public class XGraphics implements Cloneable, DirectRasterGraphics
29 {
30   static class XRaster extends MappedRaster
31   {
32     XImage ximage;
33 
XRaster(WritableRaster raster, XImage ximage, ColorModel cm)34     public XRaster(WritableRaster raster, XImage ximage, ColorModel cm)
35     {
36       super(raster, cm);
37       this.ximage = ximage;
38     }
39   }
40 
41   GC context;
42   XGraphicsConfiguration config;
43   Rectangle clipBounds;
44 
45   XFontMetrics metrics;
46 
47 
clone()48   public Object clone()
49   {
50     try
51       {
52 	XGraphics gfxCopy = (XGraphics) super.clone();
53 	gfxCopy.context = context.create();
54 
55 	return gfxCopy;
56       }
57     catch (CloneNotSupportedException ex)
58       {
59 	// This should never happen.
60 	throw new InternalError ();
61       }
62   }
63 
dispose()64   public void dispose()
65   {
66     GC lContext = context;
67     context = null;
68     config = null;
69     clipBounds = null;
70     metrics = null;
71 
72     if (lContext != null)
73     {
74       lContext.dispose();
75     }
76   }
77 
XGraphics(Drawable drawable, XGraphicsConfiguration config)78   public XGraphics(Drawable drawable, XGraphicsConfiguration config)
79   {
80     context = GC.create(drawable);
81     this.config = config;
82   }
83 
setColor(Color color)84   public void setColor(Color color)
85   {
86     if (color != null)
87       context.setForeground(config.getPixel(color));
88   }
89 
setPaintMode()90   public void setPaintMode()
91   {
92     throw new UnsupportedOperationException("not implemented");
93   }
94 
setXORMode(Color c1)95   public void setXORMode(Color c1)
96   {
97     throw new UnsupportedOperationException("not implemented");
98   }
99 
setFont(Font font)100   public void setFont(Font font)
101   {
102     if (font == null)
103       return;
104     if ((metrics != null) && font.equals(metrics.getFont()))
105       return;
106     metrics = config.getXFontMetrics(font);
107     if (metrics != null)
108       context.setFont(metrics.xfont);
109   }
110 
getFontMetrics(Font font)111   public FontMetrics getFontMetrics(Font font)
112   {
113     if ((metrics != null) && font.equals(metrics.getFont()))
114       return metrics;
115 
116     return config.getXFontMetrics(font);
117   }
118 
setClip(int x, int y, int width, int height)119   public void setClip(int x, int y, int width, int height)
120   {
121     Rectangle[] rects = { new Rectangle(x, y, width, height) };
122     context.setClipRectangles(rects);
123   }
124 
setClip(Shape clip)125   public void setClip(Shape clip)
126   {
127     /* TODO: create a special RectangleUnion shape that can be
128        used to draw advantage of the GCs ability to set multiple
129        rectangles.
130     */
131 
132     /* FIXME: creating all these objects is wasteful and can be
133        costly in the long run, since this code is run at every
134        expose. */
135     Rectangle newClipBounds = clip.getBounds();
136 
137     /* FIXME: decide whether this test code is worth anything
138      * (as of 2004-01-29, it prints frequently)
139     if ((clipBounds != null) && !clipBounds.contains(newClipBounds))
140       {
141 	System.err.println("warning: old clip ("+ clipBounds +") does " +
142 			   "not fully contain new clip (" +
143 			   newClipBounds + ")");
144       }
145      */
146     clipBounds = newClipBounds;
147     Rectangle[] rects = { clipBounds };
148     context.setClipRectangles(rects);
149   }
150 
copyArea(int x, int y, int width, int height, int dx, int dy)151   public void copyArea(int x, int y, int width, int height, int
152 		       dx, int dy)
153   {
154     throw new UnsupportedOperationException("not implemented");
155   }
156 
drawLine(int x1, int y1, int x2, int y2)157   public void drawLine(int x1, int y1, int x2, int y2)
158   {
159     context.drawLine(x1, y1, x2, y2);
160   }
161 
drawRect(int x, int y, int width, int height)162   public void drawRect(int x, int y, int width, int height)
163   {
164     throw new UnsupportedOperationException("not implemented yet");
165   }
166 
fillRect(int x, int y, int width, int height)167   public void fillRect(int x, int y, int width, int height)
168   {
169     context.fillRectangle(x, y, width, height);
170   }
171 
drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)172   public void drawArc(int x, int y, int width, int height, int
173 		      startAngle, int arcAngle)
174   {
175     context.drawArc (x, y, width, height, startAngle, arcAngle);
176   }
177 
fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)178   public void fillArc(int x, int y, int width, int height, int
179 		      startAngle, int arcAngle)
180   {
181     context.fillArc (x, y, width, height, startAngle, arcAngle);
182   }
183 
drawPolyline(int[] xPoints, int[] yPoints, int nPoints)184   public void drawPolyline(int[] xPoints, int[] yPoints, int
185 			   nPoints)
186   {
187     throw new UnsupportedOperationException("not implemented");
188   }
189 
drawPolygon(int[] xPoints, int[] yPoints, int nPoints)190   public void drawPolygon(int[] xPoints, int[] yPoints, int
191 			  nPoints)
192   {
193     throw new UnsupportedOperationException("not implemented");
194   }
195 
fillPolygon(int[] xPoints, int[] yPoints, int nPoints, int translateX, int translateY)196   public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints,
197 			  int translateX, int translateY)
198   {
199     context.fillPolygon(xPoints, yPoints, nPoints, translateX, translateY);
200   }
201 
drawString(String str, int x, int y)202   public void drawString(String str, int x, int y)
203   {
204     context.drawString(str, x, y);
205   }
206 
drawImage(Image img, int x, int y, ImageObserver observer)207   public boolean drawImage(Image img, int x, int y,
208 			   ImageObserver observer)
209   {
210     if (img instanceof XOffScreenImage)
211     {
212       // FIXME: have to enforce clip, or is it OK as-is?
213       XOffScreenImage offScreenImage = (XOffScreenImage) img;
214       Pixmap pixmap = offScreenImage.getPixmap ();
215       context.copyArea (pixmap, 0, 0, x, y,
216         offScreenImage.getWidth (), offScreenImage.getHeight ());
217       return true;
218     }
219     if (clipBounds == null)
220       return false; // ***FIXME***
221 
222     if (!(img instanceof BufferedImage))
223       {
224 	throw new AWTError("unknown image class");
225       }
226 
227     BufferedImage bimg = (BufferedImage) img;
228 
229     XImage ximg = (XImage) bimg.getProperty("gnu.gcj.xlib.XImage");
230     if (ximg == null)
231       {
232 	System.err.println("FIXME: skipping null XImage, should " +
233 			   "really do on the spot conversion");
234 	return false;
235       }
236 
237     /*
238       +------------------
239       |    clip
240       |     +---------+
241       | img |         |
242       |  +--+-------+ |
243       |  |  |       | |
244       |  |  |       | |
245       |  |  +-------+-+
246       |  |          |
247       |  +----------+
248     */
249 
250     int iLeft   = Math.max(x, clipBounds.x);
251     int iTop    = Math.max(y, clipBounds.y);
252     int iRight  = Math.min(x + bimg.getWidth(),
253 			   clipBounds.x + clipBounds.width);
254     int iBottom = Math.min(y + bimg.getHeight(),
255 			   clipBounds.y + clipBounds.height);
256 
257     int srcX = iLeft - x;
258     int srcY = iTop  - y;
259 
260     int width  = iRight  - iLeft;
261     int height = iBottom - iTop;
262 
263     if ((width > 0) && (height > 0))
264       context.putImage(ximg, srcX, srcY, iLeft, iTop, width, height);
265 
266     return true;
267   }
268 
mapRaster(Rectangle bounds)269   public MappedRaster mapRaster(Rectangle bounds)
270   {
271     Visual visual = config.getVisual();
272     XImage ximage = new XImage(visual, bounds.width, bounds.height,
273 			       false // do not auto allocate memory
274 			       );
275 
276     WritableRaster raster =
277       config.createRasterForXImage(ximage,
278 				   new Point(bounds.x, bounds.y));
279 
280     DataBuffer dataB = raster.getDataBuffer();
281     XGraphicsConfiguration.attachData(ximage, dataB, 0);
282 
283     Drawable drawable = context.getDrawable();
284 
285     // TODO: restrict to clipping
286 
287     Rectangle mBounds = drawable.copyIntoXImage(ximage, bounds, 0, 0);
288 
289     return new XRaster(raster, ximage, config.imageCM);
290   }
291 
292 
unmapRaster(MappedRaster mappedRaster)293   public void unmapRaster(MappedRaster mappedRaster)
294   {
295     XRaster xraster = (XRaster) mappedRaster;
296     XImage ximage = xraster.ximage;
297     Raster raster = xraster.getRaster();
298     int x = raster.getMinX();
299     int y = raster.getMinY();
300     int width = raster.getWidth();
301     int height = raster.getHeight();
302 
303     context.putImage(ximage, 0, 0, x, y, width, height);
304   }
305 }
306