summaryrefslogtreecommitdiff
path: root/libjava/gnu/awt/xlib/XGraphicsConfiguration.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/gnu/awt/xlib/XGraphicsConfiguration.java')
-rw-r--r--libjava/gnu/awt/xlib/XGraphicsConfiguration.java550
1 files changed, 550 insertions, 0 deletions
diff --git a/libjava/gnu/awt/xlib/XGraphicsConfiguration.java b/libjava/gnu/awt/xlib/XGraphicsConfiguration.java
new file mode 100644
index 000000000..7d527116d
--- /dev/null
+++ b/libjava/gnu/awt/xlib/XGraphicsConfiguration.java
@@ -0,0 +1,550 @@
+/* Copyright (C) 2000, 2003 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.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.Graphics2D;
+import java.awt.Graphics;
+import java.awt.GraphicsDevice;
+import java.awt.Point;
+import java.awt.Color;
+import java.awt.color.ColorSpace;
+import java.awt.Font;
+import java.awt.image.*;
+import java.awt.geom.AffineTransform;
+import gnu.gcj.xlib.GC;
+import gnu.gcj.xlib.Drawable;
+import gnu.gcj.xlib.Window;
+import gnu.gcj.xlib.XImage;
+import gnu.gcj.xlib.Visual;
+import gnu.gcj.xlib.Colormap;
+import gnu.gcj.xlib.XColor;
+import gnu.gcj.xlib.Screen;
+import gnu.gcj.xlib.Display;
+import gnu.gcj.xlib.XException;
+import gnu.java.awt.Buffers;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+public class XGraphicsConfiguration extends GraphicsConfiguration
+{
+ //public abstract GraphicsDevice getDevice();
+
+ Visual visual;
+ int format;
+ Colormap colormap;
+ ColorModel imageCM;
+ ColorModel pixelCM;
+ private static final int CACHE_SIZE_PER_DISPLAY = 10;
+ static FontMetricsCache fontMetricsCache = new FontMetricsCache ();
+
+ /** Font metrics cache class. Caches at most CACHE_SIZE_PER_DISPLAY
+ * XFontMetrics objects for each display device. When a display's cache
+ * gets full, the least-recently used entry is overwritten.
+ * XXX: lruOrder rolls over after a few billion operations, so it might
+ * on very rare occasions misinterpret which is the oldest entry
+ */
+ static class FontMetricsCache
+ {
+ private java.util.Hashtable displays = new java.util.Hashtable ();
+
+ /** Font metrics cache for a display device
+ */
+ class PerDisplayCache
+ {
+ private int lruCount = 0;
+ private java.util.Hashtable entries = new java.util.Hashtable ();
+
+ class CacheEntry
+ {
+ int lruOrder;
+ XFontMetrics fm;
+ Font font;
+ }
+
+ /** Get an entry (null if not there) and update LRU ordering
+ */
+ XFontMetrics get (Font font)
+ {
+ CacheEntry entry = (CacheEntry)entries.get (font);
+ if (entry != null)
+ {
+ entry.lruOrder = lruCount++;
+ }
+ return (entry==null) ? null : entry.fm;
+ }
+
+ /** Put an entry in the cache, eliminating the oldest entry if
+ * the cache is at capacity.
+ */
+ void put (Font font, XFontMetrics fontMetrics)
+ {
+ if (entries.size () >= CACHE_SIZE_PER_DISPLAY)
+ {
+ // cache is full -- eliminate the oldest entry
+ // slow operation, but shouldn't happen very often
+ int maxAge = 0;
+ CacheEntry oldestEntry = null;
+ int referenceCount = lruCount;
+ for (Enumeration e = entries.elements (); e.hasMoreElements ();)
+ {
+ CacheEntry entry = (CacheEntry)e.nextElement ();
+ if ((referenceCount-entry.lruOrder) > maxAge)
+ {
+ maxAge = referenceCount-entry.lruOrder;
+ oldestEntry = entry;
+ }
+ }
+ if (oldestEntry != null)
+ entries.remove (oldestEntry.font);
+ }
+ CacheEntry newEntry = new CacheEntry ();
+ newEntry.lruOrder = lruCount++;
+ newEntry.fm = fontMetrics;
+ newEntry.font = font;
+ entries.put (font,newEntry);
+ }
+ }
+
+ /** Get the font metrics for a font, if it is present in the cache.
+ * @param font The AWT font for which to find the font metrics
+ * @param display The display, to select the cached entries for that display
+ * @return The font metrics, or null if not cached
+ */
+ XFontMetrics get (Font font, Display display)
+ {
+ PerDisplayCache cache = (PerDisplayCache)displays.get (display);
+ return (cache==null) ? null : cache.get (font);
+ }
+
+ /** Put a font in the cache
+ * @param font The font
+ * @param display The display
+ * @param fontMetrics The font metrics
+ */
+ void put (Font font, Display display, XFontMetrics fontMetrics)
+ {
+ PerDisplayCache cache = (PerDisplayCache)displays.get (display);
+ if (cache == null)
+ {
+ cache = new PerDisplayCache ();
+ displays.put (display,cache);
+ }
+ cache.put (font,fontMetrics);
+ }
+ }
+
+ public XGraphicsConfiguration(Visual visual)
+ {
+ this.visual = visual;
+ }
+
+ public BufferedImage createCompatibleImage(int width, int height)
+ {
+ XImage ximg = new XImage(visual, width, height,
+ false // do not auto allocate memory
+ );
+
+ Point origin = new Point(0, 0);
+ WritableRaster raster = createRasterForXImage(ximg, origin);
+
+ /* This is not a good way of doing this. Multiple toolkits may
+ want to share the BufferedImage. */
+ Hashtable props = new Hashtable();
+ props.put("gnu.gcj.xlib.XImage", ximg);
+ props.put("java.awt.GraphicsConfiguration", this);
+
+ BufferedImage bimg = new BufferedImage(imageCM,raster, false, props);
+
+ DataBuffer dataB = raster.getDataBuffer();
+ attachData(ximg, dataB, 0);
+ return bimg;
+ }
+
+ WritableRaster createRasterForXImage(XImage ximage, Point origin)
+ {
+ if (imageCM == null) prepareColorModel(ximage);
+
+ /*
+ This will not work, since it creates a sample model that
+ does not necessarily match the format of the XImage.
+
+ WritableRaster raster =
+ imageCM.createCompatibleWritableRaster(width, height); */
+
+ // Create a sample model matching the XImage:
+
+ SampleModel imageSM = null;
+
+ int width = ximage.getWidth();
+ int height = ximage.getHeight();
+ int bitsPerPixel = ximage.getBitsPerPixel();
+ int dataType =
+ Buffers.smallestAppropriateTransferType(bitsPerPixel);
+ int bitsPerDataElement = DataBuffer.getDataTypeSize(dataType);
+ int scanlineStride = ximage.getBytesPerLine()*8/bitsPerDataElement;
+
+ if (imageCM instanceof IndexColorModel)
+ {
+ int[] bandOffsets = {0};
+ imageSM = new ComponentSampleModel(dataType,
+ width, height,
+ 1, // pixel stride
+ scanlineStride,
+ bandOffsets);
+ }
+ else if (imageCM instanceof PackedColorModel)
+ {
+ PackedColorModel pcm = (PackedColorModel) imageCM;
+ int[] masks = pcm.getMasks();
+
+ imageSM = new SinglePixelPackedSampleModel(dataType,
+ width, height,
+ scanlineStride,
+ masks);
+ }
+
+ if (imageSM == null)
+ {
+ throw new UnsupportedOperationException("creating sample model " +
+ "for " + imageCM +
+ " not implemented");
+ }
+
+ WritableRaster raster = Raster.createWritableRaster(imageSM, origin);
+ return raster;
+ }
+
+
+
+ /**
+ * Attach a the memory of a data buffer to an XImage
+ * structure. [This method is not gnu.awt.xlib specific, and should
+ * maybe be moved to a different location.]
+ *
+ * @param offset Offset to data. The given offset does not include
+ * data buffer offset, which will also be added.
+ */
+ static void attachData(XImage ximage, DataBuffer dataB, int offset)
+ {
+ offset += dataB.getOffset();
+ switch (dataB.getDataType())
+ {
+ case DataBuffer.TYPE_BYTE:
+ ximage.setData(((DataBufferByte) dataB).getData(), offset);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ ximage.setData(((DataBufferUShort) dataB).getData(), offset);
+ break;
+ case DataBuffer.TYPE_INT:
+ ximage.setData(((DataBufferInt) dataB).getData(), offset);
+ break;
+ default:
+ throw
+ new UnsupportedOperationException("Do not know how to " +
+ "set data for data " +
+ "type " +
+ dataB.getDataType());
+ }
+ }
+
+ void prepareColorModel(XImage ximage)
+ {
+ format = ximage.getFormat();
+ int bitsPerPixel = ximage.getBitsPerPixel();
+ switch (format) {
+ case XImage.ZPIXMAP_FORMAT:
+ calcZPixmapModels(bitsPerPixel);
+ break;
+
+ default:
+ throw new UnsupportedOperationException("unimplemented format");
+ }
+ }
+
+ void calcZPixmapModels(int bitsPerPixel)
+ {
+ switch (visual.getVisualClass())
+ {
+ case Visual.VC_TRUE_COLOR:
+ calcDecomposedRGBModels(bitsPerPixel);
+ break;
+ case Visual.VC_PSEUDO_COLOR:
+ calcPseudoColorModels(bitsPerPixel);
+ break;
+ default:
+ String msg = "unimplemented visual class";
+ throw new UnsupportedOperationException(msg);
+ }
+ }
+
+ void calcDecomposedRGBModels(int bitsPerPixel)
+ {
+ int dataType = Buffers.smallestAppropriateTransferType(bitsPerPixel);
+
+
+ if (DataBuffer.getDataTypeSize(dataType) == bitsPerPixel)
+ {
+ ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+
+ imageCM = new DirectColorModel(cs,
+ visual.getDepth(),
+ visual.getRedMask(),
+ visual.getGreenMask(),
+ visual.getBlueMask(),
+ 0, // no alpha
+ false,
+ dataType);
+ }
+ else
+ {
+ throw new
+ UnsupportedOperationException("unimplemented bits per pixel");
+ }
+ }
+
+ void calcPseudoColorModels(int bitsPerPixel)
+ {
+ if (colormap == null)
+ colormap = visual.getScreen().getDefaultColormap();
+
+ XColor[] colArray = colormap.getXColors();
+
+ int numCol = colArray.length;
+ byte[] rmap = new byte[numCol];
+ byte[] gmap = new byte[numCol];
+ byte[] bmap = new byte[numCol];
+ byte[] amap = new byte[numCol];
+
+ for (int i=0; i < numCol; i++)
+ {
+ XColor color = colArray[i];
+ if (color.getFlags() == Colormap.FLAG_SHARED)
+ {
+ rmap[i] = (byte) (color.getRed() >> 8);
+ gmap[i] = (byte) (color.getGreen() >> 8);
+ bmap[i] = (byte) (color.getBlue() >> 8);
+ amap[i] = (byte) 0xff;
+ } // else, leave default zero values...
+ }
+
+ imageCM = new IndexColorModel(visual.getDepth(), numCol,
+ rmap, gmap, bmap, amap);
+ }
+
+ /**
+ * Gets the associated device that this configuration describes.
+ *
+ * @return the device
+ */
+ public GraphicsDevice getDevice()
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ /**
+ * Returns a buffered image optimized to this device, so that blitting can
+ * be supported in the buffered image.
+ *
+ * @param w the width of the buffer
+ * @param h the height of the buffer
+ * @return the buffered image, or null if none is supported
+ */
+ public BufferedImage createCompatibleImage(int width,
+ int height,
+ int transparency)
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ /**
+ * Returns a buffered volatile image optimized to this device, so that
+ * blitting can be supported in the buffered image. Because the buffer is
+ * volatile, it can be optimized by native graphics accelerators.
+ *
+ * @param w the width of the buffer
+ * @param h the height of the buffer
+ * @return the buffered image, or null if none is supported
+ * @see Component#createVolatileImage(int, int)
+ * @since 1.4
+ */
+ public VolatileImage createCompatibleVolatileImage(int w, int h)
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ /**
+ * FIXME: I'm not sure which color model that should be returned here.
+ */
+ public ColorModel getColorModel()
+ {
+ if (pixelCM == null)
+ preparePixelCM();
+ return pixelCM;
+ }
+
+ void preparePixelCM()
+ {
+ switch (visual.getVisualClass())
+ {
+ case Visual.VC_TRUE_COLOR:
+ pixelCM = new DirectColorModel(visual.getDepth(),
+ visual.getRedMask(),
+ visual.getGreenMask(),
+ visual.getBlueMask());
+ break;
+ case Visual.VC_PSEUDO_COLOR:
+
+ if (colormap == null)
+ colormap = visual.getScreen().getDefaultColormap();
+
+ XColor[] colArray = colormap.getXColors();
+
+ int numCol = colArray.length;
+ byte[] rmap = new byte[numCol];
+ byte[] gmap = new byte[numCol];
+ byte[] bmap = new byte[numCol];
+ byte[] amap = new byte[numCol];
+
+ for (int i=0; i < numCol; i++)
+ {
+ XColor color = colArray[i];
+ if (color.getFlags() == Colormap.FLAG_SHARED) {
+ rmap[i] = (byte) (color.getRed() >> 8);
+ gmap[i] = (byte) (color.getGreen() >> 8);
+ bmap[i] = (byte) (color.getBlue() >> 8);
+ amap[i] = (byte) 0xff;
+ } // else, leave default zero values...
+
+ }
+
+ pixelCM = new IndexColorModel(visual.getDepth(), numCol,
+ rmap, gmap, bmap, amap);
+ break;
+ default:
+ throw new UnsupportedOperationException("not implemented");
+ }
+ }
+
+ public ColorModel getColorModel(int transparency)
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public AffineTransform getDefaultTransform()
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public AffineTransform getNormalizingTransform()
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public Rectangle getBounds()
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ Visual getVisual()
+ {
+ return visual;
+ }
+
+ /* FIXME: This should be moved to XGraphicsDevice... */
+ XFontMetrics getXFontMetrics (java.awt.Font awtFont)
+ {
+ // If the metrics object for this font is already cached, use it.
+ // Otherwise create and cache it.
+ Display display = visual.getScreen ().getDisplay ();
+ XFontMetrics fm = fontMetricsCache.get (awtFont,display);
+ if (fm == null)
+ {
+ String foundry = "*";
+ String family = awtFont.getName ();
+ String weight = awtFont.isBold () ? "bold" : "medium";
+ String slant = awtFont.isItalic () ? "i" : "r";
+ String sWidth = "*";
+ String addStyle = "";
+ String pixelSize = "*";
+ String pointSize = awtFont.getSize () + "0";
+ String xres = "*";
+ String yres = "*";
+ String spacing = "*";
+ String averageWidth = "*";
+ String charset = "iso10646-1"; // because we use functions like XDrawString16
+
+ String logicalFontDescription =
+ "-" + // FontNameRegistry prefix
+ foundry + "-" + family + "-" + weight + "-" +
+ slant + "-" + sWidth + "-" + addStyle + "-" +
+ pixelSize + "-" + pointSize + "-" + xres + "-" +
+ yres + "-" + spacing + "-" + averageWidth + "-";
+
+ // Try to load a Unicode font. If that doesn't work, try again, without
+ // specifying the character set.
+ try
+ {
+ gnu.gcj.xlib.Font xfont = new gnu.gcj.xlib.Font (display, logicalFontDescription + charset);
+ fm = new XFontMetrics (xfont, awtFont);
+ }
+ catch (XException e)
+ {
+ gnu.gcj.xlib.Font xfont = new gnu.gcj.xlib.Font (display, logicalFontDescription + "*-*");
+ fm = new XFontMetrics (xfont, awtFont);
+ }
+ fontMetricsCache.put (awtFont,display,fm);
+ }
+ return fm;
+ }
+
+ int getPixel(Color color)
+ {
+ /* FIXME: consider an integer technique whenever
+ * the ColorModel is 8 bits per color.
+ * The problem with using integers is that it doesn't work unless
+ * the colors are 8 bits each (as in the array), since ColorModel.getDataElement(int[],int)
+ * expects non-normalized values. For example, in a 16-bit display mode, you
+ * would typically have 5 bits each for red and blue, and 6 bits for green.
+ int[] components =
+ {
+ color.getRed (),
+ color.getGreen (),
+ color.getBlue (),
+ 0xff
+ };
+ */
+
+ int[] unnormalizedComponents = { 0, 0, 0, 0xff };
+ ColorModel cm = getColorModel ();
+ if (color != null)
+ {
+ float[] normalizedComponents =
+ {
+ ((float)color.getRed ()) / 255F,
+ ((float)color.getGreen ()) / 255F,
+ ((float)color.getBlue ()) / 255F,
+ 1
+ };
+ cm.getUnnormalizedComponents(normalizedComponents, 0,
+ unnormalizedComponents, 0);
+ }
+ return cm.getDataElement (unnormalizedComponents, 0);
+ }
+
+ /**
+ * @since 1.5
+ */
+ public VolatileImage createCompatibleVolatileImage (int width, int height,
+ int transparency)
+ {
+ return null;
+ }
+}