1 /* Copyright (C) 2000, 2003 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
11 import java
.awt
.GraphicsConfiguration
;
12 import java
.awt
.Rectangle
;
13 import java
.awt
.Graphics2D
;
14 import java
.awt
.Graphics
;
15 import java
.awt
.GraphicsDevice
;
16 import java
.awt
.Point
;
17 import java
.awt
.Color
;
18 import java
.awt
.color
.ColorSpace
;
20 import java
.awt
.image
.*;
21 import java
.awt
.geom
.AffineTransform
;
22 import gnu
.gcj
.xlib
.GC
;
23 import gnu
.gcj
.xlib
.Drawable
;
24 import gnu
.gcj
.xlib
.Window
;
25 import gnu
.gcj
.xlib
.XImage
;
26 import gnu
.gcj
.xlib
.Visual
;
27 import gnu
.gcj
.xlib
.Colormap
;
28 import gnu
.gcj
.xlib
.XColor
;
29 import gnu
.gcj
.xlib
.Screen
;
30 import gnu
.gcj
.xlib
.Display
;
31 import gnu
.gcj
.xlib
.XException
;
32 import gnu
.java
.awt
.Buffers
;
33 import java
.util
.Enumeration
;
34 import java
.util
.Hashtable
;
36 public class XGraphicsConfiguration
extends GraphicsConfiguration
38 //public abstract GraphicsDevice getDevice();
45 private static final int CACHE_SIZE_PER_DISPLAY
= 10;
46 static FontMetricsCache fontMetricsCache
= new FontMetricsCache ();
48 /** Font metrics cache class. Caches at most CACHE_SIZE_PER_DISPLAY
49 * XFontMetrics objects for each display device. When a display's cache
50 * gets full, the least-recently used entry is overwritten.
51 * XXX: lruOrder rolls over after a few billion operations, so it might
52 * on very rare occasions misinterpret which is the oldest entry
54 static class FontMetricsCache
56 private java
.util
.Hashtable displays
= new java
.util
.Hashtable ();
58 /** Font metrics cache for a display device
62 private int lruCount
= 0;
63 private java
.util
.Hashtable entries
= new java
.util
.Hashtable ();
72 /** Get an entry (null if not there) and update LRU ordering
74 XFontMetrics
get (Font font
)
76 CacheEntry entry
= (CacheEntry
)entries
.get (font
);
79 entry
.lruOrder
= lruCount
++;
81 return (entry
==null) ?
null : entry
.fm
;
84 /** Put an entry in the cache, eliminating the oldest entry if
85 * the cache is at capacity.
87 void put (Font font
, XFontMetrics fontMetrics
)
89 if (entries
.size () >= CACHE_SIZE_PER_DISPLAY
)
91 // cache is full -- eliminate the oldest entry
92 // slow operation, but shouldn't happen very often
94 CacheEntry oldestEntry
= null;
95 int referenceCount
= lruCount
;
96 for (Enumeration e
= entries
.elements (); e
.hasMoreElements ();)
98 CacheEntry entry
= (CacheEntry
)e
.nextElement ();
99 if ((referenceCount
-entry
.lruOrder
) > maxAge
)
101 maxAge
= referenceCount
-entry
.lruOrder
;
105 if (oldestEntry
!= null)
106 entries
.remove (oldestEntry
.font
);
108 CacheEntry newEntry
= new CacheEntry ();
109 newEntry
.lruOrder
= lruCount
++;
110 newEntry
.fm
= fontMetrics
;
111 newEntry
.font
= font
;
112 entries
.put (font
,newEntry
);
116 /** Get the font metrics for a font, if it is present in the cache.
117 * @param font The AWT font for which to find the font metrics
118 * @param display The display, to select the cached entries for that display
119 * @return The font metrics, or null if not cached
121 XFontMetrics
get (Font font
, Display display
)
123 PerDisplayCache cache
= (PerDisplayCache
)displays
.get (display
);
124 return (cache
==null) ?
null : cache
.get (font
);
127 /** Put a font in the cache
128 * @param font The font
129 * @param display The display
130 * @param fontMetrics The font metrics
132 void put (Font font
, Display display
, XFontMetrics fontMetrics
)
134 PerDisplayCache cache
= (PerDisplayCache
)displays
.get (display
);
137 cache
= new PerDisplayCache ();
138 displays
.put (display
,cache
);
140 cache
.put (font
,fontMetrics
);
144 public XGraphicsConfiguration(Visual visual
)
146 this.visual
= visual
;
149 public BufferedImage
createCompatibleImage(int width
, int height
)
151 XImage ximg
= new XImage(visual
, width
, height
,
152 false // do not auto allocate memory
155 Point origin
= new Point(0, 0);
156 WritableRaster raster
= createRasterForXImage(ximg
, origin
);
158 /* This is not a good way of doing this. Multiple toolkits may
159 want to share the BufferedImage. */
160 Hashtable props
= new Hashtable();
161 props
.put("gnu.gcj.xlib.XImage", ximg
);
162 props
.put("java.awt.GraphicsConfiguration", this);
164 BufferedImage bimg
= new BufferedImage(imageCM
,raster
, false, props
);
166 DataBuffer dataB
= raster
.getDataBuffer();
167 attachData(ximg
, dataB
, 0);
171 WritableRaster
createRasterForXImage(XImage ximage
, Point origin
)
173 if (imageCM
== null) prepareColorModel(ximage
);
176 This will not work, since it creates a sample model that
177 does not necessarily match the format of the XImage.
179 WritableRaster raster =
180 imageCM.createCompatibleWritableRaster(width, height); */
182 // Create a sample model matching the XImage:
184 SampleModel imageSM
= null;
186 int width
= ximage
.getWidth();
187 int height
= ximage
.getHeight();
188 int bitsPerPixel
= ximage
.getBitsPerPixel();
190 Buffers
.smallestAppropriateTransferType(bitsPerPixel
);
191 int bitsPerDataElement
= DataBuffer
.getDataTypeSize(dataType
);
192 int scanlineStride
= ximage
.getBytesPerLine()*8/bitsPerDataElement
;
194 if (imageCM
instanceof IndexColorModel
)
196 int[] bandOffsets
= {0};
197 imageSM
= new ComponentSampleModel(dataType
,
203 else if (imageCM
instanceof PackedColorModel
)
205 PackedColorModel pcm
= (PackedColorModel
) imageCM
;
206 int[] masks
= pcm
.getMasks();
208 imageSM
= new SinglePixelPackedSampleModel(dataType
,
216 throw new UnsupportedOperationException("creating sample model " +
221 WritableRaster raster
= Raster
.createWritableRaster(imageSM
, origin
);
228 * Attach a the memory of a data buffer to an XImage
229 * structure. [This method is not gnu.awt.xlib specific, and should
230 * maybe be moved to a different location.]
232 * @param offset Offset to data. The given offset does not include
233 * data buffer offset, which will also be added.
235 static void attachData(XImage ximage
, DataBuffer dataB
, int offset
)
237 offset
+= dataB
.getOffset();
238 switch (dataB
.getDataType())
240 case DataBuffer
.TYPE_BYTE
:
241 ximage
.setData(((DataBufferByte
) dataB
).getData(), offset
);
243 case DataBuffer
.TYPE_USHORT
:
244 ximage
.setData(((DataBufferUShort
) dataB
).getData(), offset
);
246 case DataBuffer
.TYPE_INT
:
247 ximage
.setData(((DataBufferInt
) dataB
).getData(), offset
);
251 new UnsupportedOperationException("Do not know how to " +
252 "set data for data " +
254 dataB
.getDataType());
258 void prepareColorModel(XImage ximage
)
260 format
= ximage
.getFormat();
261 int bitsPerPixel
= ximage
.getBitsPerPixel();
263 case XImage
.ZPIXMAP_FORMAT
:
264 calcZPixmapModels(bitsPerPixel
);
268 throw new UnsupportedOperationException("unimplemented format");
272 void calcZPixmapModels(int bitsPerPixel
)
274 switch (visual
.getVisualClass())
276 case Visual
.VC_TRUE_COLOR
:
277 calcDecomposedRGBModels(bitsPerPixel
);
279 case Visual
.VC_PSEUDO_COLOR
:
280 calcPseudoColorModels(bitsPerPixel
);
283 String msg
= "unimplemented visual class";
284 throw new UnsupportedOperationException(msg
);
288 void calcDecomposedRGBModels(int bitsPerPixel
)
290 int dataType
= Buffers
.smallestAppropriateTransferType(bitsPerPixel
);
293 if (DataBuffer
.getDataTypeSize(dataType
) == bitsPerPixel
)
295 ColorSpace cs
= ColorSpace
.getInstance(ColorSpace
.CS_sRGB
);
297 imageCM
= new DirectColorModel(cs
,
300 visual
.getGreenMask(),
301 visual
.getBlueMask(),
309 UnsupportedOperationException("unimplemented bits per pixel");
313 void calcPseudoColorModels(int bitsPerPixel
)
315 if (colormap
== null)
316 colormap
= visual
.getScreen().getDefaultColormap();
318 XColor
[] colArray
= colormap
.getXColors();
320 int numCol
= colArray
.length
;
321 byte[] rmap
= new byte[numCol
];
322 byte[] gmap
= new byte[numCol
];
323 byte[] bmap
= new byte[numCol
];
324 byte[] amap
= new byte[numCol
];
326 for (int i
=0; i
< numCol
; i
++)
328 XColor color
= colArray
[i
];
329 if (color
.getFlags() == Colormap
.FLAG_SHARED
)
331 rmap
[i
] = (byte) (color
.getRed() >> 8);
332 gmap
[i
] = (byte) (color
.getGreen() >> 8);
333 bmap
[i
] = (byte) (color
.getBlue() >> 8);
334 amap
[i
] = (byte) 0xff;
335 } // else, leave default zero values...
338 imageCM
= new IndexColorModel(visual
.getDepth(), numCol
,
339 rmap
, gmap
, bmap
, amap
);
343 * Gets the associated device that this configuration describes.
347 public GraphicsDevice
getDevice()
349 throw new UnsupportedOperationException("not implemented");
353 * Returns a buffered image optimized to this device, so that blitting can
354 * be supported in the buffered image.
356 * @param w the width of the buffer
357 * @param h the height of the buffer
358 * @return the buffered image, or null if none is supported
360 public BufferedImage
createCompatibleImage(int width
,
364 throw new UnsupportedOperationException("not implemented");
368 * Returns a buffered volatile image optimized to this device, so that
369 * blitting can be supported in the buffered image. Because the buffer is
370 * volatile, it can be optimized by native graphics accelerators.
372 * @param w the width of the buffer
373 * @param h the height of the buffer
374 * @return the buffered image, or null if none is supported
375 * @see Component#createVolatileImage(int, int)
378 public VolatileImage
createCompatibleVolatileImage(int w
, int h
)
380 throw new UnsupportedOperationException("not implemented");
384 * FIXME: I'm not sure which color model that should be returned here.
386 public ColorModel
getColorModel()
393 void preparePixelCM()
395 switch (visual
.getVisualClass())
397 case Visual
.VC_TRUE_COLOR
:
398 pixelCM
= new DirectColorModel(visual
.getDepth(),
400 visual
.getGreenMask(),
401 visual
.getBlueMask());
403 case Visual
.VC_PSEUDO_COLOR
:
405 if (colormap
== null)
406 colormap
= visual
.getScreen().getDefaultColormap();
408 XColor
[] colArray
= colormap
.getXColors();
410 int numCol
= colArray
.length
;
411 byte[] rmap
= new byte[numCol
];
412 byte[] gmap
= new byte[numCol
];
413 byte[] bmap
= new byte[numCol
];
414 byte[] amap
= new byte[numCol
];
416 for (int i
=0; i
< numCol
; i
++)
418 XColor color
= colArray
[i
];
419 if (color
.getFlags() == Colormap
.FLAG_SHARED
) {
420 rmap
[i
] = (byte) (color
.getRed() >> 8);
421 gmap
[i
] = (byte) (color
.getGreen() >> 8);
422 bmap
[i
] = (byte) (color
.getBlue() >> 8);
423 amap
[i
] = (byte) 0xff;
424 } // else, leave default zero values...
428 pixelCM
= new IndexColorModel(visual
.getDepth(), numCol
,
429 rmap
, gmap
, bmap
, amap
);
432 throw new UnsupportedOperationException("not implemented");
436 public ColorModel
getColorModel(int transparency
)
438 throw new UnsupportedOperationException("not implemented");
441 public AffineTransform
getDefaultTransform()
443 throw new UnsupportedOperationException("not implemented");
446 public AffineTransform
getNormalizingTransform()
448 throw new UnsupportedOperationException("not implemented");
451 public Rectangle
getBounds()
453 throw new UnsupportedOperationException("not implemented");
461 /* FIXME: This should be moved to XGraphicsDevice... */
462 XFontMetrics
getXFontMetrics (java
.awt
.Font awtFont
)
464 // If the metrics object for this font is already cached, use it.
465 // Otherwise create and cache it.
466 Display display
= visual
.getScreen ().getDisplay ();
467 XFontMetrics fm
= fontMetricsCache
.get (awtFont
,display
);
470 String foundry
= "*";
471 String family
= awtFont
.getName ();
472 String weight
= awtFont
.isBold () ?
"bold" : "medium";
473 String slant
= awtFont
.isItalic () ?
"i" : "r";
475 String addStyle
= "";
476 String pixelSize
= "*";
477 String pointSize
= awtFont
.getSize () + "0";
480 String spacing
= "*";
481 String averageWidth
= "*";
482 String charset
= "iso10646-1"; // because we use functions like XDrawString16
484 String logicalFontDescription
=
485 "-" + // FontNameRegistry prefix
486 foundry
+ "-" + family
+ "-" + weight
+ "-" +
487 slant
+ "-" + sWidth
+ "-" + addStyle
+ "-" +
488 pixelSize
+ "-" + pointSize
+ "-" + xres
+ "-" +
489 yres
+ "-" + spacing
+ "-" + averageWidth
+ "-";
491 // Try to load a Unicode font. If that doesn't work, try again, without
492 // specifying the character set.
495 gnu
.gcj
.xlib
.Font xfont
= new gnu
.gcj
.xlib
.Font (display
, logicalFontDescription
+ charset
);
496 fm
= new XFontMetrics (xfont
, awtFont
);
500 gnu
.gcj
.xlib
.Font xfont
= new gnu
.gcj
.xlib
.Font (display
, logicalFontDescription
+ "*-*");
501 fm
= new XFontMetrics (xfont
, awtFont
);
503 fontMetricsCache
.put (awtFont
,display
,fm
);
508 int getPixel(Color color
)
510 /* FIXME: consider an integer technique whenever
511 * the ColorModel is 8 bits per color.
512 * The problem with using integers is that it doesn't work unless
513 * the colors are 8 bits each (as in the array), since ColorModel.getDataElement(int[],int)
514 * expects non-normalized values. For example, in a 16-bit display mode, you
515 * would typically have 5 bits each for red and blue, and 6 bits for green.
525 float[] normalizedComponents
=
527 ((float)color
.getRed ()) / 255F
,
528 ((float)color
.getGreen ()) / 255F
,
529 ((float)color
.getBlue ()) / 255F
,
532 int[] unnormalizedComponents
= { 0, 0, 0, 0xff };
533 ColorModel cm
= getColorModel ();
534 cm
.getUnnormalizedComponents(normalizedComponents
, 0,
535 unnormalizedComponents
, 0);
536 return cm
.getDataElement (unnormalizedComponents
, 0);