Merge with trank @ 137446
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / x / XGraphics2D.java
blob95129666a054306cafb04500f40bfe4183192c2e
1 /* XGraphics2D.java -- A Java based Graphics2D impl for X
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.java.awt.peer.x;
40 import java.awt.Color;
41 import java.awt.Font;
42 import java.awt.Graphics;
43 import java.awt.GraphicsConfiguration;
44 import java.awt.Image;
45 import java.awt.Paint;
46 import java.awt.Rectangle;
47 import java.awt.Shape;
48 import java.awt.Toolkit;
49 import java.awt.Transparency;
50 import java.awt.geom.AffineTransform;
51 import java.awt.image.BufferedImage;
52 import java.awt.image.ColorModel;
53 import java.awt.image.DataBuffer;
54 import java.awt.image.ImageObserver;
55 import java.awt.image.Raster;
56 import java.awt.peer.FontPeer;
57 import java.util.HashMap;
58 import java.util.WeakHashMap;
60 import gnu.java.awt.image.AsyncImage;
61 import gnu.java.awt.java2d.AbstractGraphics2D;
62 import gnu.java.awt.java2d.ScanlineCoverage;
63 import gnu.x11.Colormap;
64 import gnu.x11.Drawable;
65 import gnu.x11.GC;
66 import gnu.x11.image.ZPixmap;
68 public class XGraphics2D
69 extends AbstractGraphics2D
72 /**
73 * When this property is set to true, then images are always rendered as
74 * opaque images, ignoring their translucence. This is intended for
75 * debugging and demonstration purposes.
77 private static final boolean RENDER_OPAQUE =
78 Boolean.getBoolean("escherpeer.renderopaque");
80 /**
81 * The X Drawable to draw on.
83 private Drawable xdrawable;
85 /**
86 * The X graphics context (GC).
88 private GC xgc;
90 /**
91 * Indicates if this graphics has already been disposed.
93 private boolean disposed;
95 /**
96 * The current foreground color, possibly null.
98 private Color foreground;
100 XGraphics2D(Drawable d)
102 super();
103 xdrawable = d;
104 xgc = new GC(d);
105 init();
106 disposed = false;
107 //setClip(new Rectangle(0, 0, xdrawable.width, xdrawable.height));
110 @Override
111 protected void rawDrawLine(int x0, int y0, int x1, int y1)
113 xdrawable.segment(xgc, x0, y0, x1, y1);
116 @Override
117 protected void rawDrawRect(int x, int y, int w, int h)
119 xdrawable.rectangle(xgc, x, y, w, h, false);
122 @Override
123 protected void rawFillRect(int x, int y, int w, int h)
125 xdrawable.rectangle(xgc, x, y, w, h, true);
129 * Returns the color model of this Graphics object.
131 * @return the color model of this Graphics object
133 protected ColorModel getColorModel()
135 return Toolkit.getDefaultToolkit().getColorModel();
139 * Returns the color model of the target device.
141 * @return the color model of the target device
143 protected ColorModel getDestinationColorModel()
145 return Toolkit.getDefaultToolkit().getColorModel();
149 * Returns the bounds of the target.
151 * @return the bounds of the target
153 protected Rectangle getDeviceBounds()
155 return new Rectangle(0, 0, xdrawable.width, xdrawable.height);
158 public GraphicsConfiguration getDeviceConfiguration()
160 // FIXME: Implement this.
161 throw new UnsupportedOperationException("Not yet implemented");
164 public void dispose()
166 if (!disposed)
168 xgc.free();
169 xdrawable.display.flush();
170 disposed = true;
174 public Graphics create()
176 // super.create() returns a copy created by clone(), so it should
177 // be a XGraphics2D.
178 XGraphics2D copy = (XGraphics2D) super.create();
179 copy.xgc = xgc.copy();
180 return copy;
183 public void setClip(Shape c)
185 super.setClip(c);
186 if (c instanceof Rectangle)
188 Rectangle r = (Rectangle) c;
189 AffineTransform t = getTransform();
190 int translateX = (int) t.getTranslateX();
191 //System.err.println("translateX: " + translateX);
192 int translateY = (int) t.getTranslateY();
193 //System.err.println("translateY: " + translateY);
194 //System.err.println("clip: " + c);
195 gnu.x11.Rectangle clip = new gnu.x11.Rectangle(r.x, r.y, r.width,
196 r.height);
197 xgc.set_clip_rectangles(translateX, translateY,
198 new gnu.x11.Rectangle[]{clip}, GC.UN_SORTED);
203 * Notifies the backend that the raster has changed in the specified
204 * rectangular area. The raster that is provided in this method is always
205 * the same as the one returned in {@link #getDestinationRaster}.
206 * Backends that reflect changes to this raster directly don't need to do
207 * anything here.
209 * @param raster the updated raster, identical to the raster returned
210 * by {@link #getDestinationRaster()}
211 * @param x the upper left corner of the updated region, X coordinate
212 * @param y the upper lef corner of the updated region, Y coordinate
213 * @param w the width of the updated region
214 * @param h the height of the updated region
216 protected void updateRaster(Raster raster, int x, int y, int w, int h)
218 if (w > 0 && h > 0)
220 ZPixmap zPixmap = new ZPixmap(xdrawable.display, w, h,
221 xdrawable.display.default_pixmap_format);
222 int[] pixel = null;
223 int x1 = x + w;
224 int y1 = y + h;
225 for (int tx = x; tx < x1; tx++)
227 for (int ty = y; ty < y1; ty++)
229 pixel = raster.getPixel(tx, ty, pixel);
230 //System.err.println("tx: " + tx + ", ty: " + ty + ", pixel: " + pixel[0] + ", " + pixel[1] + ", " + pixel[2]);
231 // System.err.print("r: " + pixel[0]);
232 // System.err.print(", g: " + pixel[1]);
233 // System.err.println(", b: " + pixel[2]);
234 zPixmap.set_red(tx - x, ty - y, pixel[0]);
235 zPixmap.set_green(tx - x, ty - y, pixel[1]);
236 zPixmap.set_blue(tx - x, ty - y, pixel[2]);
239 xdrawable.put_image(xgc, zPixmap, x, y);
243 @Override
244 public void renderScanline(int y, ScanlineCoverage c)
246 if (y >= xdrawable.height)
247 return;
249 // TODO: Handle Composite and Paint.
250 ScanlineCoverage.Iterator iter = c.iterate();
251 int coverageAlpha = 0;
252 int maxCoverage = c.getMaxCoverage();
253 while (iter.hasNext())
255 ScanlineCoverage.Range range = iter.next();
257 coverageAlpha = range.getCoverage();
258 int x0 = range.getXPos();
259 int l = range.getLength();
260 if (coverageAlpha == c.getMaxCoverage())
262 // Simply paint the current color over the existing pixels.
263 xdrawable.fill_rectangle(xgc, x0, y, l, 1);
265 else if (coverageAlpha > 0)
267 // Composite the current color with the existing pixels.
268 int x1 = x0 + l;
269 x0 = Math.min(Math.max(0, x0), xdrawable.width - 1);
270 x1 = Math.min(Math.max(0, x1), xdrawable.width - 1);
271 if ((x1 - x0) < 1)
272 continue;
273 l = x1 - x0;
274 gnu.x11.image.ZPixmap existing = (ZPixmap)
275 xdrawable.image(x0, y, l, 1, 0xFFFFFFFF,
276 gnu.x11.image.Image.Format.ZPIXMAP);
277 for (int x = 0; x < l; x++)
279 Color col = getColor();
280 if (col == null)
282 col = Color.BLACK;
284 int red = col.getRed();
285 int green = col.getGreen();
286 int blue = col.getBlue();
287 int redOut = existing.get_red(x, 0);
288 int greenOut = existing.get_green(x, 0);
289 int blueOut = existing.get_blue(x, 0);
290 int outAlpha = maxCoverage - coverageAlpha;
291 redOut = redOut * outAlpha + red * coverageAlpha;
292 redOut = redOut / maxCoverage;
293 greenOut = greenOut * outAlpha + green * coverageAlpha;
294 greenOut = greenOut / maxCoverage;
295 blueOut = blueOut * outAlpha + blue * coverageAlpha;
296 blueOut = blueOut / maxCoverage;
297 existing.set(x, 0, redOut, greenOut, blueOut);
299 xdrawable.put_image(xgc, existing, x0, y);
304 protected void init()
306 super.init();
309 public void setPaint(Paint p)
311 super.setPaint(p);
312 if (p instanceof Color)
314 // TODO: Optimize for different standard bit-depths.
315 Color c = (Color) p;
316 XToolkit tk = (XToolkit) Toolkit.getDefaultToolkit();
317 HashMap colorMap = tk.colorMap;
318 gnu.x11.Color col = (gnu.x11.Color) colorMap.get(c);
319 if (col == null)
321 Colormap map = xdrawable.display.default_colormap;
322 col = map.alloc_color (c.getRed() * 256,
323 c.getGreen() * 256,
324 c.getBlue() * 256);
325 colorMap.put(c, col);
327 xgc.set_foreground(col);
328 foreground = c;
332 protected void fillShape(Shape s, boolean isFont)
334 synchronized (xdrawable.display) {
335 super.fillShape(s, isFont);
339 private static WeakHashMap<Image,ZPixmap> imageCache = new WeakHashMap<Image,ZPixmap>();
341 protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs)
343 image = unwrap(image);
344 boolean ret;
345 if (image instanceof XImage)
347 XImage xImage = (XImage) image;
348 xdrawable.copy_area(xImage.pixmap, xgc, 0, 0, xImage.getWidth(obs),
349 xImage.getHeight(obs), x, y);
350 ret = true;
352 else if (image instanceof PixmapVolatileImage)
354 PixmapVolatileImage pvi = (PixmapVolatileImage) image;
355 xdrawable.copy_area(pvi.getPixmap(), xgc, 0, 0, pvi.getWidth(obs),
356 pvi.getHeight(obs), x, y);
357 ret = true;
359 else if (image instanceof BufferedImage)
361 BufferedImage bi = (BufferedImage) image;
362 DataBuffer db = bi.getRaster().getDataBuffer();
363 if (db instanceof ZPixmapDataBuffer)
365 ZPixmapDataBuffer zpmdb = (ZPixmapDataBuffer) db;
366 ZPixmap zpixmap = zpmdb.getZPixmap();
367 xdrawable.put_image(xgc, zpixmap, x, y);
368 ret = true;
370 else
372 int transparency = bi.getTransparency();
373 int w = bi.getWidth();
374 int h = bi.getHeight();
375 if (imageCache.containsKey(image))
377 ZPixmap zpixmap = imageCache.get(image);
378 xdrawable.put_image(xgc, zpixmap, x, y);
380 else if (transparency == Transparency.OPAQUE || RENDER_OPAQUE)
382 XGraphicsDevice gd = XToolkit.getDefaultDevice();
383 ZPixmap zpixmap = new ZPixmap(gd.getDisplay(), w, h);
384 for (int yy = 0; yy < h; yy++)
386 for (int xx = 0; xx < w; xx++)
388 int rgb = bi.getRGB(xx, yy);
389 zpixmap.set(xx, yy, rgb);
392 xdrawable.put_image(xgc, zpixmap, x, y);
393 imageCache.put(image, zpixmap);
394 } else {
395 ZPixmap zpixmap = (ZPixmap) xdrawable.image(x, y, w, h,
396 0xffffffff,
397 gnu.x11.image.Image.Format.ZPIXMAP);
398 for (int yy = 0; yy < h; yy++)
400 for (int xx = 0; xx < w; xx++)
402 int rgb = bi.getRGB(xx, yy);
403 int alpha = 0xff & (rgb >> 24);
404 if (alpha == 0)
406 // Completely translucent.
407 rgb = zpixmap.get_red(xx, yy) << 16
408 | zpixmap.get_green(xx, yy) << 8
409 | zpixmap.get_blue(xx, yy);
411 else if (alpha < 255)
413 // Composite pixels.
414 int red = 0xff & (rgb >> 16);
415 red = red * alpha
416 + (255 - alpha) * zpixmap.get_red(xx, yy);
417 red = red / 255;
418 int green = 0xff & (rgb >> 8);
419 green = green * alpha
420 + (255 - alpha) * zpixmap.get_green(xx, yy);
421 green = green / 255;
422 int blue = 0xff & rgb;
423 blue = blue * alpha
424 + (255 - alpha) * zpixmap.get_blue(xx, yy);
425 blue = blue / 255;
426 rgb = red << 16 | green << 8 | blue;
428 // else keep rgb value from source image.
430 zpixmap.set(xx, yy, rgb);
433 xdrawable.put_image(xgc, zpixmap, x, y);
434 // We can't cache prerendered translucent images, because
435 // we never know how the background changes.
437 ret = true;
440 else
442 ret = super.rawDrawImage(image, x, y, obs);
444 return ret;
447 public void setFont(Font f)
449 super.setFont(f);
450 FontPeer p = getFont().getPeer();
451 if (p instanceof XFontPeer)
453 XFontPeer xFontPeer = (XFontPeer) p;
454 xgc.set_font(xFontPeer.getXFont());
458 public void drawString(String s, int x, int y)
460 FontPeer p = getFont().getPeer();
461 if (p instanceof XFontPeer)
463 int tx = (int) transform.getTranslateX();
464 int ty = (int) transform.getTranslateY();
465 xdrawable.text(xgc, x + tx, y + ty, s);
467 else
469 super.drawString(s, x, y);
474 * Extracts an image instance out of an AsyncImage. If the image isn't
475 * an AsyncImage, then the original instance is returned.
477 * @param im the image
479 * @return the image to render
481 private Image unwrap(Image im)
483 Image image = im;
484 if (image instanceof AsyncImage)
486 AsyncImage aIm = (AsyncImage) image;
487 image = aIm.getRealImage();
489 return image;