summaryrefslogtreecommitdiff
path: root/gnu/java
diff options
context:
space:
mode:
authorRoman Kennke <roman@kennke.org>2007-09-20 14:01:05 +0000
committerRoman Kennke <roman@kennke.org>2007-09-20 14:01:05 +0000
commit3eaf3f44a0e41fea77a3e39535b17d455d056a49 (patch)
tree479662ece4a19a7488466852d0f9876beec69306 /gnu/java
parentdf7bb76cd9404208c6a9acc97bc96380a7a210ba (diff)
downloadclasspath-3eaf3f44a0e41fea77a3e39535b17d455d056a49.tar.gz
2007-09-20 Roman Kennke <roman.kennke@aicas.com>
* gnu/java/awt/font/GNUGlyphVector.java (cleanOutline): New field, caches the untransformed outline. (getOutline()): No need to validate here. Already done in getOutline(float,float). (getOutline(float,float)): Cache untransformed outlines. Protect returned shape from modification by wrapping in ShapeWrapper object. * gnu/java/awt/font/OpenTypeFontPeer.java: New class. Implements ClasspathFontPeer for OpenType fonts. * gnu/java/awt/java2d/AbstractGraphics2D.java (DEFAULT_TEXT_AA): New constant/property for controlling default anti-aliasing for text. (GC_CACHE_SIZE): New constant for the size of the glyph vector cache. (shapeCache): Don't make shapeCache thread local. This wouldn't gain much, because the event dispatch thread is restarted quite often. (scanlineConverters): Don't make scanlineConverters thread local, but instead pool them into a list. (gvCache): New cache for glyph vectors. (searchTextKey): New static field, a shared key used for GV caching. (drawString): Cache glyph vectors. (getFontRenderContext): Protect the current transform from beeing changed. (clone): Check clip for null when cloning. (drawLine): Use shared shape cache. No need for calling a method here. (drawRect): Likewise. Add translation to rectangle coordinates. (fillRect): Use shared shape cache. No need for calling a method here. (drawRoundRect): Likewise. (fillRoundRect): Likewise. (drawOval): Likewise. (fillOval): Likewise. (drawArc): Likewise. (fillArc): Likewise. (drawPolyline): Likewise. (drawPolygon): Likewise. (fillPolygon): Likewise. (fillShape): Check property for default text AA. Set Y resolution. (rawDrawLine): Use shared shape cache. No need for calling a method here. (rawDrawRect): Likewise. (rawFillRect): Likewise. (rawDrawString): Removed. Subclasses override drawString() instead. (getShapeCache): Removed. No longer needed. (getScanlineConverter): New helper method for pooling scanline converters. (freeScanlineConverter): New helper method for pooling scanline converters. * gnu/java/awt/java2d/PixelCoverage.java: New class. Used by the reworked scanline converter. * gnu/java/awt/java2d/ScanlineConverter.java (Y_RESOLUTION): Removed. The Y resolution is now specified by the caller. (yResolution): New field. Stores the Y resolution. (renderShape): Take y resolution as argument. (setResolution): Take y resolution as argument. * gnu/java/awt/java2d/ShapeWrapper.java: New class. Protects shape objects from modification by application code. * gnu/java/awt/java2d/TextCacheKey.java: New class. Used for caching GlyphVectors. * gnu/java/awt/peer/x/XFontPeer2.java: Removed. This is now implemented in OpenTypeFontPeer now. * gnu/java/awt/peer/x/XEventPump.java (handleEvent): Check insets. * gnu/java/awt/peer/x/XFontPeer.java Changed class and method names for changed Escher API. (clinit): Use font properties from xfonts.properties. (canDisplay): Changed to take int argument. * gnu/java/awt/peer/x/XFramePeer.java (XFramePeer): Set the title of the frame on creation time. (setTitle): Implemented. * gnu/java/awt/peer/x/XGraphics2D.java (imageCache): New field. Caches native representations for images. (drawString): New method. Optimized version for X fonts. (fillScanline): Removed. (fillScanlineAA): Removed. (rawDrawImage): Optimized drawing for ZPixmap-backed images. (rawDrawRect): Optimized rectangle drawing. (renderScanline): Added compositing code. (setFont): Overridden for X font support. (setPaint): Added TODO. * gnu/java/awt/peer/x/XGraphicsConfiguration.java (getSize): New helper method for XToolkit. (getResolution): New helper method for XToolkit. * gnu/java/awt/peer/x/XGraphicsEnvironment.java (getAvailableFontFamilyNames): Implemented. * gnu/java/awt/peer/x/XToolkit.java (fontCache): New field for caching fonts. (getClasspathFontPeer): Cache fonts. (getScreenSize): Implemented. (getScreenResolution): Implemented. (getFontList): Implemented. (isModalExclusionTypeSupported): New method. (isModalityTypeSupported): New method. * gnu/java/awt/peer/x/XWindowPeer.java (insets): New field for storing the insets of the frame. (XWindowPeer): Set correct decoration. (getGraphics): Set foreground, background and font. (show): Determine the correct frame extents. (reshape): Only resize when not inside callback. (insets): Implemented correctly. (getFontMetrics): Use OpenTypeFontPeer. * gnu/java/awt/peer/x/ZPixmapDataBuffer.java (getZPixmap): New method. This is used in XGraphics2D for drawing the buffer. * gnu/java/util/LRUCache.java: New class. Implements an LRU cache.
Diffstat (limited to 'gnu/java')
-rw-r--r--gnu/java/awt/font/GNUGlyphVector.java40
-rw-r--r--gnu/java/awt/font/OpenTypeFontPeer.java (renamed from gnu/java/awt/peer/x/XFontPeer2.java)169
-rw-r--r--gnu/java/awt/java2d/AbstractGraphics2D.java165
-rw-r--r--gnu/java/awt/java2d/PixelCoverage.java132
-rw-r--r--gnu/java/awt/java2d/ScanlineConverter.java29
-rw-r--r--gnu/java/awt/java2d/ShapeWrapper.java119
-rw-r--r--gnu/java/awt/java2d/TextCacheKey.java153
-rw-r--r--gnu/java/awt/peer/x/XEventPump.java17
-rw-r--r--gnu/java/awt/peer/x/XFontPeer.java768
-rw-r--r--gnu/java/awt/peer/x/XFramePeer.java4
-rw-r--r--gnu/java/awt/peer/x/XGraphics2D.java202
-rw-r--r--gnu/java/awt/peer/x/XGraphicsConfiguration.java38
-rw-r--r--gnu/java/awt/peer/x/XGraphicsEnvironment.java9
-rw-r--r--gnu/java/awt/peer/x/XToolkit.java66
-rw-r--r--gnu/java/awt/peer/x/XWindowPeer.java114
-rw-r--r--gnu/java/awt/peer/x/ZPixmapDataBuffer.java5
-rw-r--r--gnu/java/util/LRUCache.java77
17 files changed, 1874 insertions, 233 deletions
diff --git a/gnu/java/awt/font/GNUGlyphVector.java b/gnu/java/awt/font/GNUGlyphVector.java
index 2f73dce77..22f331e15 100644
--- a/gnu/java/awt/font/GNUGlyphVector.java
+++ b/gnu/java/awt/font/GNUGlyphVector.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package gnu.java.awt.font;
+import gnu.java.awt.java2d.ShapeWrapper;
+
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
@@ -82,6 +84,10 @@ public class GNUGlyphVector
private AffineTransform[] transforms;
private int layoutFlags;
+ /**
+ * The cached non-transformed outline of this glyph vector.
+ */
+ private Shape cleanOutline;
/**
* Constructs a new GNUGlyphVector.
@@ -257,7 +263,6 @@ public class GNUGlyphVector
*/
public Shape getOutline()
{
- validate();
return getOutline(0.0f, 0.0f);
}
@@ -273,16 +278,33 @@ public class GNUGlyphVector
{
validate();
- GeneralPath outline = new GeneralPath();
- int len = glyphs.length;
- for (int i = 0; i < len; i++)
+ Shape outline;
+ if (cleanOutline == null)
{
- GeneralPath p = new GeneralPath(getGlyphOutline(i));
- outline.append(p, false);
+ GeneralPath path = new GeneralPath();
+ int len = glyphs.length;
+ for (int i = 0; i < len; i++)
+ {
+ GeneralPath p = new GeneralPath(getGlyphOutline(i));
+ path.append(p, false);
+ }
+ // Protect the cached instance from beeing modified by application
+ // code.
+ cleanOutline = new ShapeWrapper(path);
+ outline = cleanOutline;
+ }
+ else
+ {
+ outline = cleanOutline;
+ }
+ if (x != 0 || y != 0)
+ {
+ GeneralPath path = new GeneralPath(outline);
+ AffineTransform t = new AffineTransform();
+ t.translate(x, y);
+ path.transform(t);
+ outline = path;
}
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- outline.transform(t);
return outline;
}
diff --git a/gnu/java/awt/peer/x/XFontPeer2.java b/gnu/java/awt/font/OpenTypeFontPeer.java
index ab3861be1..2d898a448 100644
--- a/gnu/java/awt/peer/x/XFontPeer2.java
+++ b/gnu/java/awt/font/OpenTypeFontPeer.java
@@ -35,7 +35,7 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-package gnu.java.awt.peer.x;
+package gnu.java.awt.font;
import java.awt.Font;
import java.awt.FontMetrics;
@@ -54,15 +54,16 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
-import gnu.java.awt.font.FontDelegate;
-import gnu.java.awt.font.FontFactory;
import gnu.java.awt.peer.ClasspathFontPeer;
-public class XFontPeer2
+public class OpenTypeFontPeer
extends ClasspathFontPeer
{
@@ -70,10 +71,21 @@ public class XFontPeer2
* The font mapping as specified in the file fonts.properties.
*/
private static Properties fontProperties;
+
+ /**
+ * The available font family names.
+ */
+ private static Set<String> availableFontNames;
+
+ /**
+ * Font spec to file mapping.
+ */
+ private static Map<String,Map<String,String>> fontToFileMap;
+
static
{
fontProperties = new Properties();
- InputStream in = XFontPeer2.class.getResourceAsStream("fonts.properties");
+ InputStream in = OpenTypeFontPeer.class.getResourceAsStream("fonts.properties");
try
{
fontProperties.load(in);
@@ -234,12 +246,14 @@ public class XFontPeer2
private FontDelegate fontDelegate;
- XFontPeer2(String name, int style, int size)
+ public OpenTypeFontPeer(String name, int style, int size)
{
super(name, style, size);
try
{
- File fontfile = new File("/usr/share/fonts/truetype/freefont/FreeSans.ttf");
+ String fontSpec = encodeFont(name, style);
+ String filename = mapFontToFilename(fontSpec);
+ File fontfile = new File(filename);
FileInputStream in = new FileInputStream(fontfile);
FileChannel ch = in.getChannel();
ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
@@ -252,12 +266,14 @@ public class XFontPeer2
}
}
- XFontPeer2(String name, Map atts)
+ public OpenTypeFontPeer(String name, Map atts)
{
super(name, atts);
try
{
- File fontfile = new File("/usr/share/fonts/truetype/freefont/FreeSans.ttf");
+ String fontSpec = encodeFont(name, atts);
+ String filename = mapFontToFilename(fontSpec);
+ File fontfile = new File(filename);
FileInputStream in = new FileInputStream(fontfile);
FileChannel ch = in.getChannel();
ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
@@ -371,7 +387,7 @@ public class XFontPeer2
*
* @return the encoded font description
*/
- static String encodeFont(String name, Map atts)
+ public static String encodeFont(String name, Map atts)
{
String family = name;
if (family == null || family.equals(""))
@@ -379,11 +395,6 @@ public class XFontPeer2
if (family == null)
family = "SansSerif";
- int size = 12;
- Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
- if (sizeFl != null)
- size = sizeFl.intValue();
-
int style = 0;
// Detect italic attribute.
Float posture = (Float) atts.get(TextAttribute.POSTURE);
@@ -395,49 +406,43 @@ public class XFontPeer2
if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
style |= Font.BOLD;
- return encodeFont(name, style, size);
+ return encodeFont(name, style);
}
/**
- * Encodes a font name + style + size specification into a X logical font
- * description (XLFD) as described here:
- *
- * http://www.meretrx.com/e93/docs/xlfd.html
+ * Encodes a font name + style into a combined string.
*
* This is implemented to look up the font description in the
* fonts.properties of this package.
*
* @param name the font name
* @param style the font style
- * @param size the font size
*
* @return the encoded font description
*/
- static String encodeFont(String name, int style, int size)
+ static String encodeFont(String name, int style)
{
StringBuilder key = new StringBuilder();
key.append(validName(name));
- key.append('.');
+ key.append('/');
switch (style)
{
case Font.BOLD:
- key.append("bold");
+ key.append("b");
break;
case Font.ITALIC:
- key.append("italic");
+ key.append("i");
break;
case (Font.BOLD | Font.ITALIC):
- key.append("bolditalic");
+ key.append("bi");
break;
case Font.PLAIN:
default:
- key.append("plain");
+ key.append("p");
}
- String protoType = fontProperties.getProperty(key.toString());
- int s = size;
- return protoType.replaceFirst("%d", String.valueOf(s * 10));
+ return key.toString();
}
/**
@@ -451,18 +456,108 @@ public class XFontPeer2
static String validName(String name)
{
String retVal;
- if (name.equalsIgnoreCase("sansserif")
- || name.equalsIgnoreCase("serif")
- || name.equalsIgnoreCase("monospaced")
- || name.equalsIgnoreCase("dialog")
- || name.equalsIgnoreCase("dialoginput"))
+ Set<String> fontNames = getFontNames();
+ if (fontNames.contains(name))
{
- retVal = name.toLowerCase();
+ retVal = name;
}
else
{
- retVal = "sansserif";
+ retVal = "SansSerif";
}
return retVal;
}
+
+ public static String[] getAvailableFontFamilyNames(Locale l)
+ {
+ Set<String> fontNames = getFontNames();
+ int numNames = fontNames.size();
+ String[] ret = fontNames.toArray(new String[numNames]);
+ return ret;
+ }
+
+ private static synchronized Set<String> getFontNames()
+ {
+ if (availableFontNames == null)
+ {
+ HashSet<String> familyNames = new HashSet<String>();
+ for (Object o : fontProperties.keySet())
+ {
+ if (o instanceof String)
+ {
+ String key = (String) o;
+ int slashIndex = key.indexOf('/');
+ String name = key.substring(0, slashIndex);
+ familyNames.add(name);
+ }
+ }
+ availableFontNames = familyNames;
+ }
+ return availableFontNames;
+ }
+
+ /**
+ * Takes a font spec as returned by {@link #encodeFont(String, int)},
+ * and returns the corresponding font file, or <code>null</code> if no such
+ * font mapping exists.
+ *
+ * @param fontSpec font name and style as returned by
+ * {@link #encodeFont(String, int)}
+ *
+ * @return filename of the corresponding font file
+ */
+ private synchronized String mapFontToFilename(String fontSpec)
+ {
+ if (fontToFileMap == null)
+ {
+ fontToFileMap = new HashMap<String,Map<String,String>>();
+
+ // Initialize font spec to file mapping according to the
+ // font.properties.
+ for (Object o : fontProperties.keySet())
+ {
+ if (o instanceof String)
+ {
+ String key = (String) o;
+ int slashIndex = key.indexOf('/');
+ String name = key.substring(0, slashIndex);
+ String spec = key.substring(slashIndex + 1);
+ // Handle aliases in the 2nd pass below.
+ if (! spec.equals("a"))
+ {
+ Map<String,String> specToFileMap = fontToFileMap.get(name);
+ if (specToFileMap == null)
+ {
+ specToFileMap = new HashMap<String,String>();
+ fontToFileMap.put(name, specToFileMap);
+ }
+ specToFileMap.put(spec, fontProperties.getProperty(key));
+ }
+ }
+ }
+ // 2nd pass for handling aliases.
+ for (Object o : fontProperties.keySet())
+ {
+ if (o instanceof String)
+ {
+ String key = (String) o;
+ int slashIndex = key.indexOf('/');
+ String name = key.substring(0, slashIndex);
+ String spec = key.substring(slashIndex + 1);
+ // Handle aliases in the 2nd pass below.
+ if (spec.equals("a"))
+ {
+ String alias = fontProperties.getProperty(key);
+ Map<String,String> specToFileMap = fontToFileMap.get(alias);
+ fontToFileMap.put(name, specToFileMap);
+ }
+ }
+ }
+ }
+ // Look up font file.
+ int slashIndex = fontSpec.indexOf('/');
+ String name = fontSpec.substring(0, slashIndex);
+ String spec = fontSpec.substring(slashIndex + 1);
+ return fontToFileMap.get(name).get(spec);
+ }
}
diff --git a/gnu/java/awt/java2d/AbstractGraphics2D.java b/gnu/java/awt/java2d/AbstractGraphics2D.java
index 15ec90da1..36ba0f430 100644
--- a/gnu/java/awt/java2d/AbstractGraphics2D.java
+++ b/gnu/java/awt/java2d/AbstractGraphics2D.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package gnu.java.awt.java2d;
+import gnu.java.util.LRUCache;
+
import java.awt.AWTError;
import java.awt.AlphaComposite;
import java.awt.AWTPermission;
@@ -80,7 +82,9 @@ import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Map;
/**
@@ -152,22 +156,46 @@ public abstract class AbstractGraphics2D
{
/**
+ * Wether we use anti aliasing for rendering text by default or not.
+ */
+ private static final boolean DEFAULT_TEXT_AA =
+ Boolean.getBoolean("gnu.java2d.default_text_aa");
+
+ /**
* The default font to use on the graphics object.
*/
private static final Font FONT = new Font("SansSerif", Font.PLAIN, 12);
/**
+ * The size of the LRU cache used for caching GlyphVectors.
+ */
+ private static final int GV_CACHE_SIZE = 50;
+
+ /**
* Caches certain shapes to avoid massive creation of such Shapes in
* the various draw* and fill* methods.
*/
- private static final ThreadLocal<ShapeCache> shapeCache =
- new ThreadLocal<ShapeCache>();
+ private static final ShapeCache shapeCache = new ShapeCache();
+
+ /**
+ * A pool of scanline converters. It is important to reuse scanline
+ * converters because they keep their datastructures in place. We pool them
+ * for use in multiple threads.
+ */
+ private static final LinkedList<ScanlineConverter> scanlineConverters =
+ new LinkedList<ScanlineConverter>();
+
+ /**
+ * Caches glyph vectors for better drawing performance.
+ */
+ private static final Map<TextCacheKey,GlyphVector> gvCache =
+ Collections.synchronizedMap(new LRUCache<TextCacheKey,GlyphVector>(GV_CACHE_SIZE));
/**
- * The scanline converters by thread.
+ * This key is used to search in the gvCache without allocating a new
+ * key each time.
*/
- private static final ThreadLocal<ScanlineConverter> scanlineConverters =
- new ThreadLocal<ScanlineConverter>();
+ private static final TextCacheKey searchTextKey = new TextCacheKey();
/**
* The transformation for this Graphics2D instance
@@ -484,14 +512,25 @@ public abstract class AbstractGraphics2D
*/
public void drawString(String text, int x, int y)
{
- if (isOptimized)
- rawDrawString(text, x, y);
- else
+ GlyphVector gv;
+ synchronized (searchTextKey)
{
- FontRenderContext ctx = getFontRenderContext();
- GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray());
- drawGlyphVector(gv, x, y);
+ TextCacheKey tck = searchTextKey;
+ FontRenderContext frc = getFontRenderContext();
+ tck.setString(text);
+ tck.setFont(font);
+ tck.setFontRenderContext(frc);
+ if (gvCache.containsKey(tck))
+ {
+ gv = gvCache.get(tck);
+ }
+ else
+ {
+ gv = font.createGlyphVector(frc, text.toCharArray());
+ gvCache.put(new TextCacheKey(text, font, frc), gv);
+ }
}
+ drawGlyphVector(gv, x, y);
}
/**
@@ -949,7 +988,10 @@ public abstract class AbstractGraphics2D
public FontRenderContext getFontRenderContext()
{
- return new FontRenderContext(transform, false, true);
+ // Protect our own transform from beeing modified.
+ AffineTransform tf = new AffineTransform(transform);
+ // TODO: Determine antialias and fractionalmetrics parameters correctly.
+ return new FontRenderContext(tf, false, true);
}
/**
@@ -992,8 +1034,10 @@ public abstract class AbstractGraphics2D
// Copy the clip. If it's a Rectangle, preserve that for optimization.
if (clip instanceof Rectangle)
copy.clip = new Rectangle((Rectangle) clip);
- else
+ else if (clip != null)
copy.clip = new GeneralPath(clip);
+ else
+ copy.clip = null;
copy.renderingHints = new RenderingHints(null);
copy.renderingHints.putAll(renderingHints);
@@ -1163,7 +1207,7 @@ public abstract class AbstractGraphics2D
}
else
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.line == null)
sc.line = new Line2D.Float();
sc.line.setLine(x1, y1, x2, y2);
@@ -1175,11 +1219,13 @@ public abstract class AbstractGraphics2D
{
if (isOptimized)
{
- rawDrawRect(x, y, w, h);
+ int tx = (int) transform.getTranslateX();
+ int ty = (int) transform.getTranslateY();
+ rawDrawRect(x + tx, y + ty, w, h);
}
else
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.rect == null)
sc.rect = new Rectangle();
sc.rect.setBounds(x, y, w, h);
@@ -1204,7 +1250,7 @@ public abstract class AbstractGraphics2D
}
else
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.rect == null)
sc.rect = new Rectangle();
sc.rect.setBounds(x, y, width, height);
@@ -1249,7 +1295,7 @@ public abstract class AbstractGraphics2D
public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
int arcHeight)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.roundRect == null)
sc.roundRect = new RoundRectangle2D.Float();
sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
@@ -1269,7 +1315,7 @@ public abstract class AbstractGraphics2D
public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
int arcHeight)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.roundRect == null)
sc.roundRect = new RoundRectangle2D.Float();
sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
@@ -1286,7 +1332,7 @@ public abstract class AbstractGraphics2D
*/
public void drawOval(int x, int y, int width, int height)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.ellipse == null)
sc.ellipse = new Ellipse2D.Float();
sc.ellipse.setFrame(x, y, width, height);
@@ -1303,7 +1349,7 @@ public abstract class AbstractGraphics2D
*/
public void fillOval(int x, int y, int width, int height)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.ellipse == null)
sc.ellipse = new Ellipse2D.Float();
sc.ellipse.setFrame(x, y, width, height);
@@ -1316,7 +1362,7 @@ public abstract class AbstractGraphics2D
public void drawArc(int x, int y, int width, int height, int arcStart,
int arcAngle)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.arc == null)
sc.arc = new Arc2D.Float();
sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN);
@@ -1329,7 +1375,7 @@ public abstract class AbstractGraphics2D
public void fillArc(int x, int y, int width, int height, int arcStart,
int arcAngle)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.arc == null)
sc.arc = new Arc2D.Float();
sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE);
@@ -1338,7 +1384,7 @@ public abstract class AbstractGraphics2D
public void drawPolyline(int[] xPoints, int[] yPoints, int npoints)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.polyline == null)
sc.polyline = new GeneralPath();
GeneralPath p = sc.polyline;
@@ -1355,7 +1401,7 @@ public abstract class AbstractGraphics2D
*/
public void drawPolygon(int[] xPoints, int[] yPoints, int npoints)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.polygon == null)
sc.polygon = new Polygon();
sc.polygon.reset();
@@ -1370,7 +1416,7 @@ public abstract class AbstractGraphics2D
*/
public void fillPolygon(int[] xPoints, int[] yPoints, int npoints)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.polygon == null)
sc.polygon = new Polygon();
sc.polygon.reset();
@@ -1559,8 +1605,9 @@ public abstract class AbstractGraphics2D
{
Object v = renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
// We default to antialiasing for text rendering.
- antialias = (v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON
- || v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
+ antialias = v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON
+ || (v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT
+ && DEFAULT_TEXT_AA);
}
else
{
@@ -1569,12 +1616,15 @@ public abstract class AbstractGraphics2D
}
ScanlineConverter sc = getScanlineConverter();
int resolution = 0;
+ int yRes = 0;
if (antialias)
{
// Adjust resolution according to rendering hints.
resolution = 2;
+ yRes = 4;
}
- sc.renderShape(this, s, clip, transform, resolution, renderingHints);
+ sc.renderShape(this, s, clip, transform, resolution, yRes, renderingHints);
+ freeScanlineConverter(sc);
}
/**
@@ -1606,7 +1656,7 @@ public abstract class AbstractGraphics2D
*/
protected void rawDrawLine(int x0, int y0, int x1, int y1)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.line == null)
sc.line = new Line2D.Float();
sc.line.setLine(x0, y0, x1, y1);
@@ -1615,7 +1665,7 @@ public abstract class AbstractGraphics2D
protected void rawDrawRect(int x, int y, int w, int h)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.rect == null)
sc.rect = new Rectangle();
sc.rect.setBounds(x, y, w, h);
@@ -1623,22 +1673,6 @@ public abstract class AbstractGraphics2D
}
/**
- * Draws a string in optimization mode. The implementation should respect the
- * clip and translation. It can assume that the clip is a rectangle and that
- * the transform is only a translating transform.
- *
- * @param text the string to be drawn
- * @param x the start of the baseline, X coordinate
- * @param y the start of the baseline, Y coordinate
- */
- protected void rawDrawString(String text, int x, int y)
- {
- FontRenderContext ctx = getFontRenderContext();
- GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray());
- drawGlyphVector(gv, x, y);
- }
-
- /**
* Clears a rectangle in optimization mode. The implementation should respect the
* clip and translation. It can assume that the clip is a rectangle and that
* the transform is only a translating transform.
@@ -1667,7 +1701,7 @@ public abstract class AbstractGraphics2D
*/
protected void rawFillRect(int x, int y, int w, int h)
{
- ShapeCache sc = getShapeCache();
+ ShapeCache sc = shapeCache;
if (sc.rect == null)
sc.rect = new Rectangle();
sc.rect.setBounds(x, y, w, h);
@@ -1918,35 +1952,38 @@ public abstract class AbstractGraphics2D
}
/**
- * Returns the ShapeCache for the calling thread.
+ * Returns a free scanline converter from the pool.
*
- * @return the ShapeCache for the calling thread
+ * @return a scanline converter
*/
- private ShapeCache getShapeCache()
+ private ScanlineConverter getScanlineConverter()
{
- ShapeCache sc = shapeCache.get();
- if (sc == null)
+ synchronized (scanlineConverters)
{
- sc = new ShapeCache();
- shapeCache.set(sc);
+ ScanlineConverter sc;
+ if (scanlineConverters.size() > 0)
+ {
+ sc = scanlineConverters.removeFirst();
+ }
+ else
+ {
+ sc = new ScanlineConverter();
+ }
+ return sc;
}
- return sc;
}
/**
- * Returns the scanline converter for this thread.
+ * Puts a scanline converter back in the pool.
*
- * @return the scanline converter for this thread
+ * @param sc
*/
- private ScanlineConverter getScanlineConverter()
+ private void freeScanlineConverter(ScanlineConverter sc)
{
- ScanlineConverter sc = scanlineConverters.get();
- if (sc == null)
+ synchronized (scanlineConverters)
{
- sc = new ScanlineConverter();
- scanlineConverters.set(sc);
+ scanlineConverters.addLast(sc);
}
- return sc;
}
}
diff --git a/gnu/java/awt/java2d/PixelCoverage.java b/gnu/java/awt/java2d/PixelCoverage.java
new file mode 100644
index 000000000..c83ad1fff
--- /dev/null
+++ b/gnu/java/awt/java2d/PixelCoverage.java
@@ -0,0 +1,132 @@
+package gnu.java.awt.java2d;
+
+/**
+ * Stores and handles the pixel converage for a scanline. The pixel coverage
+ * is stored as sorted list of buckets, each of which holds information about
+ * the coverage for the X and Y axis. This is utilized to compute the actual
+ * coverage for each pixel on the scanline and finding chunks of pixels with
+ * equal coverage.
+ */
+final class PixelCoverage
+{
+
+ /**
+ * One bucket in the list.
+ */
+ private static final class Bucket
+ {
+ /**
+ * The X coordinate on the scanline to which this bucket belongs.
+ */
+ int xPos;
+
+ /**
+ * The X coverage.
+ */
+ int xCov;
+
+ /**
+ * The Y coverage.
+ */
+ int yCov;
+
+ /**
+ * Implements a linked list. This points to the next element of the list.
+ */
+ Bucket next;
+
+ /**
+ * Implements a linked list. This points to the previous element of the
+ * list.
+ */
+ Bucket prev;
+ }
+
+ /**
+ * The head of the sorted list of buckets.
+ */
+ private Bucket head;
+
+ /**
+ * The current bucket. We make use of the fact that the scanline converter
+ * always scans the scanline (and thus this list) from left to right to
+ * quickly find buckets or insertion points.
+ */
+ private Bucket current;
+
+ /**
+ * The bucket after the last valid bucket. Unused buckets are not thrown
+ * away and garbage collected. Instead, we keep them at the tail of the list
+ * and reuse them when necessary.
+ */
+ private Bucket last;
+
+ /**
+ * Indicates the the next scan of the scanline begins and that the next
+ * request will be at the beginning of this list. This makes searching and
+ * sorting of this list very quick.
+ */
+ void rewind()
+ {
+ current = head;
+ }
+
+ /**
+ * Clears the list. This does not throw away the old buckets but only
+ * resets the end-pointer of the list to the first element. All buckets are
+ * then unused and are reused when the list is filled again.
+ */
+ void clear()
+ {
+ last = head;
+ }
+
+ /**
+ * This adds the specified x and y coverage to the pixel at the specified
+ * X position.
+ *
+ * @param x the X position
+ * @param xc the x coverage
+ * @param yc the y coverage
+ */
+ void add(int x, int xc, int yc)
+ {
+ Bucket bucket = findOrInsert(x);
+ bucket.xCov += xc;
+ bucket.yCov += yc;
+ }
+
+ /**
+ * Finds the bucket in the list with the specified X coordinate.
+ * If no such bucket is found, then a new one is fetched (either a cached
+ * bucket from the end of the list or a newly allocated one) inserted at the
+ * correct position and returned.
+ *
+ * @param x the X coordinate
+ *
+ * @return a bucket to hold the coverage data
+ */
+ private Bucket findOrInsert(int x)
+ {
+ // First search for a matching bucket.
+ if (head == null)
+ {
+ // Special case: the list is still empty.
+ head = new Bucket();
+ current = head;
+ return head;
+ }
+
+ // This performs a linear search, starting from the current bucket.
+ // This is reasonably efficient because access to this list is always done
+ // in a linear fashion and we are not more then 1 or 2 buckets away from
+ // the one we're looking for.
+ Bucket match = current;
+ while (match != null && match.xPos != x)
+ {
+
+ }
+
+ return match;
+ }
+}
diff --git a/gnu/java/awt/java2d/ScanlineConverter.java b/gnu/java/awt/java2d/ScanlineConverter.java
index 2693a0b70..cc4bbef28 100644
--- a/gnu/java/awt/java2d/ScanlineConverter.java
+++ b/gnu/java/awt/java2d/ScanlineConverter.java
@@ -62,11 +62,6 @@ public final class ScanlineConverter
private static int ONE = Fixed.fixedValue(FIXED_DIGITS, 1);
/**
- * The number of significant bits for the Y resolution.
- */
- private static int Y_RESOLUTION = 4;
-
- /**
* The actual number of scanlines.
*/
private int numScanlines;
@@ -94,6 +89,11 @@ public final class ScanlineConverter
private int resolution;
/**
+ * The number of significant bits for the 'Y' resolution.
+ */
+ private int yResolution;
+
+ /**
* One half step according to the resolution. This is stored to avoid
* unnecessary operations during rendering.
*/
@@ -145,14 +145,15 @@ public final class ScanlineConverter
* @param trans the transform
*/
public void renderShape(Pixelizer p, Shape shape, Shape clip,
- AffineTransform trans, int res, RenderingHints hints)
+ AffineTransform trans, int res, int yRes,
+ RenderingHints hints)
{
// TODO: Do something useful with the rendering hints. Like, adjusting
// the resolution.
// Prepare resolution and upper bounds.
clear();
- setResolution(res);
+ setResolution(res, yRes);
boolean haveClip = clip != null;
@@ -278,10 +279,10 @@ public final class ScanlineConverter
int frac0 = ONE - Fixed.trunc(FIXED_DIGITS, x0);
int frac1 = ONE - Fixed.trunc(FIXED_DIGITS, x1);
// Only keep the first 4 digits after the point.
- frac0 = frac0 >> (FIXED_DIGITS - Y_RESOLUTION);
- frac1 = frac1 >> (FIXED_DIGITS - Y_RESOLUTION);
- scanlineCoverage.add(pix0, 1 * (1 << Y_RESOLUTION), frac0);
- scanlineCoverage.add(pix1, -1 * (1 << Y_RESOLUTION), -frac1);
+ frac0 = frac0 >> (FIXED_DIGITS - yResolution);
+ frac1 = frac1 >> (FIXED_DIGITS - yResolution);
+ scanlineCoverage.add(pix0, 1 * (1 << yResolution), frac0);
+ scanlineCoverage.add(pix1, -1 * (1 << yResolution), -frac1);
}
if (edge.isClip)
inClip = ! inClip;
@@ -306,14 +307,16 @@ public final class ScanlineConverter
*
* @param res the resolution
*/
- private void setResolution(int res)
+ private void setResolution(int res, int yRes)
{
int scanlinesPerPixel = 1 << res;
int one = Fixed.fixedValue(FIXED_DIGITS, 1);
resolution = one / (scanlinesPerPixel);
halfStep = resolution / 2;
- scanlineCoverage.setMaxCoverage(scanlinesPerPixel << Y_RESOLUTION);
+ scanlineCoverage.setMaxCoverage(scanlinesPerPixel << yResolution);
+
+ yResolution = yRes;
}
/**
diff --git a/gnu/java/awt/java2d/ShapeWrapper.java b/gnu/java/awt/java2d/ShapeWrapper.java
new file mode 100644
index 000000000..f4e77f450
--- /dev/null
+++ b/gnu/java/awt/java2d/ShapeWrapper.java
@@ -0,0 +1,119 @@
+/* ShapeWrapper.java -- Protects shapes by wrapping them
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.java2d;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Protects any other shape from beeing modified by wrapping it.
+ */
+public class ShapeWrapper
+ implements Shape
+{
+
+ /**
+ * The shape to be protected.
+ */
+ private Shape shape;
+
+ /**
+ * Creates a new ShapeWrapper.
+ *
+ * @param other the shape to be protected
+ */
+ public ShapeWrapper(Shape other)
+ {
+ shape = other;
+ }
+
+ public boolean contains(double x, double y)
+ {
+ return shape.contains(x, y);
+ }
+
+ public boolean contains(Point2D p)
+ {
+ return shape.contains(p);
+ }
+
+ public boolean contains(double x, double y, double w, double h)
+ {
+ return shape.contains(x, y, w, h);
+ }
+
+ public boolean contains(Rectangle2D r)
+ {
+ return shape.contains(r);
+ }
+
+ public Rectangle getBounds()
+ {
+ return shape.getBounds();
+ }
+
+ public Rectangle2D getBounds2D()
+ {
+ return shape.getBounds2D();
+ }
+
+ public PathIterator getPathIterator(AffineTransform transform)
+ {
+ return shape.getPathIterator(transform);
+ }
+
+ public PathIterator getPathIterator(AffineTransform transform, double flatness)
+ {
+ return shape.getPathIterator(transform, flatness);
+ }
+
+ public boolean intersects(double x, double y, double w, double h)
+ {
+ return shape.intersects(x, y, w, h);
+ }
+
+ public boolean intersects(Rectangle2D r)
+ {
+ return shape.intersects(r);
+ }
+
+}
diff --git a/gnu/java/awt/java2d/TextCacheKey.java b/gnu/java/awt/java2d/TextCacheKey.java
new file mode 100644
index 000000000..0a60c6226
--- /dev/null
+++ b/gnu/java/awt/java2d/TextCacheKey.java
@@ -0,0 +1,153 @@
+/* TextCacheKey.java -- Key to use for caching texts with their rendered layout
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.java2d;
+
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+
+/**
+ * A key object to be used when caching pre-rendered text.
+ */
+public class TextCacheKey
+{
+
+ /**
+ * The actual string.
+ */
+ private String string;
+
+ /**
+ * The font render context.
+ */
+ private FontRenderContext fontRenderContext;
+
+ /**
+ * The font.
+ */
+ private Font font;
+
+ /**
+ * Creates a new TextCacheKey.
+ *
+ * This is intended to be used as search key. It is important to initialize
+ * the values using the setter methods before using this key, otherwise
+ * it will throw NPEs.
+ */
+ public TextCacheKey()
+ {
+ // No-arg constructor.
+ }
+
+ /**
+ * Creates a new TextCacheKey with initial values.
+ *
+ * @param s the string
+ * @param f the font
+ * @param frc the font render context
+ */
+ public TextCacheKey(String s, Font f, FontRenderContext frc)
+ {
+ string = s;
+ font = f;
+ fontRenderContext = frc;
+ }
+
+ /**
+ * Re-sets the string. This is intented to be used in search keys only.
+ *
+ * @param s the string to set
+ */
+ public void setString(String s)
+ {
+ string = s;
+ }
+
+ /**
+ * Sets the font render context.
+ * This is intented to be used in search keys only.
+ *
+ * @param frc the new font render context
+ */
+ public void setFontRenderContext(FontRenderContext frc)
+ {
+ fontRenderContext = frc;
+ }
+
+ /**
+ * Sets the font.
+ * This is intented to be used in search keys only.
+ *
+ * @param f the font to set
+ */
+ public void setFont(Font f)
+ {
+ font = f;
+ }
+
+ /**
+ * Determines if two objects are equal.
+ *
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object o)
+ {
+ boolean eq;
+ if (o instanceof TextCacheKey)
+ {
+ TextCacheKey other = (TextCacheKey) o;
+ eq = other.string.equals(string)
+ && other.font.equals(font)
+ && other.fontRenderContext.equals(fontRenderContext);
+ }
+ else
+ {
+ eq = false;
+ }
+ return eq;
+ }
+
+ /**
+ * Computes a hashcode for this key.
+ *
+ * @see Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return string.hashCode() ^ font.hashCode() ^ fontRenderContext.hashCode();
+ }
+}
diff --git a/gnu/java/awt/peer/x/XEventPump.java b/gnu/java/awt/peer/x/XEventPump.java
index d376619c5..7f9843533 100644
--- a/gnu/java/awt/peer/x/XEventPump.java
+++ b/gnu/java/awt/peer/x/XEventPump.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package gnu.java.awt.peer.x;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
@@ -223,16 +224,21 @@ public class XEventPump
System.err.println("resize request for window id: " + key);
// Detect and report size changes.
- if (c.width() != awtWindow.getWidth()
- || c.height() != awtWindow.getHeight())
+ XWindowPeer xwindow = (XWindowPeer) awtWindow.getPeer();
+ Insets i = xwindow.insets();
+ if (c.width() != awtWindow.getWidth() - i.left - i.right
+ || c.height() != awtWindow.getHeight() - i.top - i.bottom)
{
if (XToolkit.DEBUG)
System.err.println("Setting size on AWT window: " + c.width()
+ ", " + c.height() + ", " + awtWindow.getWidth()
+ ", " + awtWindow.getHeight());
- ((XWindowPeer) awtWindow.getPeer()).callback = true;
- awtWindow.setSize(c.width(), c.height());
- ((XWindowPeer) awtWindow.getPeer()).callback = false;
+ xwindow.callback = true;
+ xwindow.xwindow.width = c.width();
+ xwindow.xwindow.height = c.height();
+ awtWindow.setSize(c.width() + i.left + i.right,
+ c.height() + i.top + i.bottom);
+ xwindow.callback = false;
}
break;
case Expose.CODE:
@@ -245,6 +251,7 @@ public class XEventPump
exp.height());
//System.err.println("expose paint: " + r);
// We need to clear the background of the exposed rectangle.
+ assert awtWindow != null : "awtWindow == null for window ID: " + key;
Graphics g = awtWindow.getGraphics();
g.clearRect(r.x, r.y, r.width, r.height);
g.dispose();
diff --git a/gnu/java/awt/peer/x/XFontPeer.java b/gnu/java/awt/peer/x/XFontPeer.java
new file mode 100644
index 000000000..0a96a613b
--- /dev/null
+++ b/gnu/java/awt/peer/x/XFontPeer.java
@@ -0,0 +1,768 @@
+/* XFontPeer.java -- The font peer for X
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.awt.peer.x;
+
+import java.awt.AWTError;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextAttribute;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.CharacterIterator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+
+import gnu.java.awt.peer.ClasspathFontPeer;
+import gnu.x11.Display;
+import gnu.x11.Fontable;
+
+/**
+ * The bridge from AWT to X fonts.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class XFontPeer
+ extends ClasspathFontPeer
+{
+
+ /**
+ * The font mapping as specified in the file fonts.properties.
+ */
+ private static Properties fontProperties;
+ static
+ {
+ fontProperties = new Properties();
+ InputStream in = XFontPeer.class.getResourceAsStream("xfonts.properties");
+ try
+ {
+ fontProperties.load(in);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * The FontMetrics implementation for XFontPeer.
+ */
+ private class XFontMetrics
+ extends FontMetrics
+ {
+ /**
+ * The ascent of the font.
+ */
+ int ascent;
+
+ /**
+ * The descent of the font.
+ */
+ int descent;
+
+ /**
+ * The maximum of the character advances.
+ */
+ private int maxAdvance;
+
+ /**
+ * The internal leading.
+ */
+ int leading;
+
+ /**
+ * Cached string metrics. This caches string metrics locally so that the
+ * server doesn't have to be asked each time.
+ */
+ private HashMap metricsCache;
+
+ /**
+ * The widths of the characters indexed by the characters themselves.
+ */
+ private int[] charWidths;
+
+ /**
+ * Creates a new XFontMetrics for the specified font.
+ *
+ * @param font the font
+ */
+ protected XFontMetrics(Font font)
+ {
+ super(font);
+ metricsCache = new HashMap();
+ Fontable.FontInfo info = getXFont().info();
+ ascent = info.font_ascent();
+ descent = info.font_descent();
+ maxAdvance = info.max_bounds().character_width();
+ leading = 0; // TODO: Not provided by X. Possible not needed.
+
+ if (info.min_byte1() == 0 && info.max_byte1() == 0)
+ readCharWidthsLinear(info);
+ else
+ readCharWidthsNonLinear(info);
+ }
+
+ /**
+ * Reads the character widths when specified in a linear fashion. That is
+ * when the min-byte1 and max-byte2 fields are both zero in the X protocol.
+ *
+ * @param info the font info reply
+ */
+ private void readCharWidthsLinear(Fontable.FontInfo info)
+ {
+ int startIndex = info.min_char_or_byte2();
+ int endIndex = info.max_char_or_byte2();
+ charWidths = new int[endIndex + 1];
+ // All the characters before startIndex are zero width.
+ for (int i = 0; i < startIndex; i++)
+ {
+ charWidths[i] = 0;
+ }
+ // All the other character info is fetched from the font info.
+ int index = startIndex;
+ Fontable.FontInfo.CharInfo[] charInfos = info.char_infos();
+ for (Fontable.FontInfo.CharInfo charInfo : charInfos)
+ {
+ charWidths[index] = charInfo.character_width();
+ index++;
+ }
+ }
+
+ private void readCharWidthsNonLinear(Fontable.FontInfo info)
+ {
+ // TODO: Implement.
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ /**
+ * Returns the ascent of the font.
+ *
+ * @return the ascent of the font
+ */
+ public int getAscent()
+ {
+ return ascent;
+ }
+
+ /**
+ * Returns the descent of the font.
+ *
+ * @return the descent of the font
+ */
+ public int getDescent()
+ {
+ return descent;
+ }
+
+ /**
+ * Returns the overall height of the font. This is the distance from
+ * baseline to baseline (usually ascent + descent + leading).
+ *
+ * @return the overall height of the font
+ */
+ public int getHeight()
+ {
+ return ascent + descent;
+ }
+
+ /**
+ * Returns the leading of the font.
+ *
+ * @return the leading of the font
+ */
+ public int getLeading()
+ {
+ return leading;
+ }
+
+ /**
+ * Returns the maximum advance for this font.
+ *
+ * @return the maximum advance for this font
+ */
+ public int getMaxAdvance()
+ {
+ return maxAdvance;
+ }
+
+ /**
+ * Determines the width of the specified character <code>c</code>.
+ *
+ * @param c the character
+ *
+ * @return the width of the character
+ */
+ public int charWidth(char c)
+ {
+ int width;
+ if (c > charWidths.length)
+ width = charWidths['?'];
+ else
+ width = charWidths[c];
+ return width;
+ }
+
+ /**
+ * Determines the overall width of the specified string.
+ *
+ * @param c the char buffer holding the string
+ * @param offset the starting offset of the string in the buffer
+ * @param length the number of characters in the string buffer
+ *
+ * @return the overall width of the specified string
+ */
+ public int charsWidth(char[] c, int offset, int length)
+ {
+ int width = 0;
+ if (c.length > 0 && length > 0)
+ {
+ String s = new String(c, offset, length);
+ width = stringWidth(s);
+ }
+ return width;
+ }
+
+ /**
+ * Determines the overall width of the specified string.
+ *
+ * @param s the string
+ *
+ * @return the overall width of the specified string
+ */
+ public int stringWidth(String s)
+ {
+ int width = 0;
+ if (s.length() > 0)
+ {
+ if (metricsCache.containsKey(s))
+ {
+ width = ((Integer) metricsCache.get(s)).intValue();
+ }
+ else
+ {
+ Fontable.TextExtentInfo extents = getXFont().text_extent(s);
+ /*
+ System.err.println("string: '" + s + "' : ");
+ System.err.println("ascent: " + extents.getAscent());
+ System.err.println("descent: " + extents.getDescent());
+ System.err.println("overall ascent: " + extents.getOverallAscent());
+ System.err.println("overall descent: " + extents.getOverallDescent());
+ System.err.println("overall width: " + extents.getOverallWidth());
+ System.err.println("overall left: " + extents.getOverallLeft());
+ System.err.println("overall right: " + extents.getOverallRight());
+ */
+ width = extents.overall_width(); // + extents.overall_left();
+ //System.err.println("String: " + s + ", width: " + width);
+ metricsCache.put(s, new Integer(width));
+ }
+ }
+ //System.err.print("stringWidth: '" + s + "': ");
+ //System.err.println(width);
+ return width;
+ }
+ }
+
+ /**
+ * The LineMetrics implementation for the XFontPeer.
+ */
+ private class XLineMetrics
+ extends LineMetrics
+ {
+
+ /**
+ * Returns the ascent of the font.
+ *
+ * @return the ascent of the font
+ */
+ public float getAscent()
+ {
+ return fontMetrics.ascent;
+ }
+
+ public int getBaselineIndex()
+ {
+ // FIXME: Implement this.
+ throw new UnsupportedOperationException();
+ }
+
+ public float[] getBaselineOffsets()
+ {
+ // FIXME: Implement this.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the descent of the font.
+ *
+ * @return the descent of the font
+ */
+ public float getDescent()
+ {
+ return fontMetrics.descent;
+ }
+
+ /**
+ * Returns the overall height of the font. This is the distance from
+ * baseline to baseline (usually ascent + descent + leading).
+ *
+ * @return the overall height of the font
+ */
+ public float getHeight()
+ {
+ return fontMetrics.ascent + fontMetrics.descent;
+ }
+
+ /**
+ * Returns the leading of the font.
+ *
+ * @return the leading of the font
+ */
+ public float getLeading()
+ {
+ return fontMetrics.leading;
+ }
+
+ public int getNumChars()
+ {
+ // FIXME: Implement this.
+ throw new UnsupportedOperationException();
+ }
+
+ public float getStrikethroughOffset()
+ {
+ return 0.F; // TODO: Provided by X??
+ }
+
+ public float getStrikethroughThickness()
+ {
+ return 1.F; // TODO: Provided by X??
+ }
+
+ public float getUnderlineOffset()
+ {
+ return 0.F; // TODO: Provided by X??
+ }
+
+ public float getUnderlineThickness()
+ {
+ return 1.F; // TODO: Provided by X??
+ }
+
+ }
+
+ /**
+ * The X font.
+ */
+ private gnu.x11.Font xfont;
+
+ private String name;
+
+ private int style;
+
+ private int size;
+
+ /**
+ * The font metrics for this font.
+ */
+ XFontMetrics fontMetrics;
+
+ /**
+ * Creates a new XFontPeer for the specified font name, style and size.
+ *
+ * @param name the font name
+ * @param style the font style (bold / italic / normal)
+ * @param size the size of the font
+ */
+ public XFontPeer(String name, int style, int size)
+ {
+ super(name, style, size);
+ this.name = name;
+ this.style = style;
+ this.size = size;
+ }
+
+ /**
+ * Creates a new XFontPeer for the specified font name and style
+ * attributes.
+ *
+ * @param name the font name
+ * @param atts the font attributes
+ */
+ public XFontPeer(String name, Map atts)
+ {
+ super(name, atts);
+ String family = name;
+ if (family == null || family.equals(""))
+ family = (String) atts.get(TextAttribute.FAMILY);
+ if (family == null)
+ family = "SansSerif";
+
+ int size = 12;
+ Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
+ if (sizeFl != null)
+ size = sizeFl.intValue();
+
+ int style = 0;
+ // Detect italic attribute.
+ Float posture = (Float) atts.get(TextAttribute.POSTURE);
+ if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
+ style |= Font.ITALIC;
+
+ // Detect bold attribute.
+ Float weight = (Float) atts.get(TextAttribute.WEIGHT);
+ if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
+ style |= Font.BOLD;
+
+ this.name = name;
+ this.style = style;
+ this.size = size;
+ }
+
+ /**
+ * Initializes the font peer with the specified attributes. This method is
+ * called from both constructors.
+ *
+ * @param name the font name
+ * @param style the font style
+ * @param size the font size
+ */
+ private void init(String name, int style, int size)
+ {
+ if (name == null)
+ {
+ name = "SansSerif";
+ }
+ GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice dev = env.getDefaultScreenDevice();
+ if (dev instanceof XGraphicsDevice)
+ {
+ Display display = ((XGraphicsDevice) dev).getDisplay();
+ String fontDescr = encodeFont(name, style, size);
+ if (XToolkit.DEBUG)
+ System.err.println("XLFD font description: " + fontDescr);
+ xfont = new gnu.x11.Font(display, fontDescr);
+ }
+ else
+ {
+ throw new AWTError("Local GraphicsEnvironment is not XWindowGraphicsEnvironment");
+ }
+ }
+
+ public boolean canDisplay(Font font, int c)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public String getSubFamilyName(Font font, Locale locale)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public String getPostScriptName(Font font)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public int getNumGlyphs(Font font)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public int getMissingGlyphCode(Font font)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public byte getBaselineFor(Font font, char c)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public String getGlyphName(Font font, int glyphIndex)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public GlyphVector createGlyphVector(Font font, FontRenderContext frc,
+ CharacterIterator ci)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public GlyphVector createGlyphVector(Font font, FontRenderContext ctx,
+ int[] glyphCodes)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc,
+ char[] chars, int start, int limit,
+ int flags)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the font metrics for the specified font.
+ *
+ * @param font the font for which to fetch the font metrics
+ *
+ * @return the font metrics for the specified font
+ */
+ public FontMetrics getFontMetrics(Font font)
+ {
+ if (font.getPeer() != this)
+ throw new AWTError("The specified font has a different peer than this");
+
+ if (fontMetrics == null)
+ fontMetrics = new XFontMetrics(font);
+ return fontMetrics;
+ }
+
+ /**
+ * Frees the font in the X server.
+ */
+ protected void finalize()
+ {
+ if (xfont != null)
+ xfont.close();
+ }
+
+ public boolean hasUniformLineMetrics(Font font)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the line metrics for this font and the specified string and
+ * font render context.
+ */
+ public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin,
+ int limit, FontRenderContext rc)
+ {
+ return new XLineMetrics();
+ }
+
+ public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ public Rectangle2D getStringBounds(Font font, CharacterIterator ci,
+ int begin, int limit, FontRenderContext frc)
+ {
+ // TODO: Implement this.
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ /**
+ * Encodes a font name + style + size specification into a X logical font
+ * description (XLFD) as described here:
+ *
+ * http://www.meretrx.com/e93/docs/xlfd.html
+ *
+ * This is implemented to look up the font description in the
+ * fonts.properties of this package.
+ *
+ * @param name the font name
+ * @param atts the text attributes
+ *
+ * @return the encoded font description
+ */
+ static String encodeFont(String name, Map atts)
+ {
+ String family = name;
+ if (family == null || family.equals(""))
+ family = (String) atts.get(TextAttribute.FAMILY);
+ if (family == null)
+ family = "SansSerif";
+
+ int size = 12;
+ Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
+ if (sizeFl != null)
+ size = sizeFl.intValue();
+
+ int style = 0;
+ // Detect italic attribute.
+ Float posture = (Float) atts.get(TextAttribute.POSTURE);
+ if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
+ style |= Font.ITALIC;
+
+ // Detect bold attribute.
+ Float weight = (Float) atts.get(TextAttribute.WEIGHT);
+ if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
+ style |= Font.BOLD;
+
+ return encodeFont(family, style, size);
+ }
+
+ /**
+ * Encodes a font name + style + size specification into a X logical font
+ * description (XLFD) as described here:
+ *
+ * http://www.meretrx.com/e93/docs/xlfd.html
+ *
+ * This is implemented to look up the font description in the
+ * fonts.properties of this package.
+ *
+ * @param name the font name
+ * @param style the font style
+ * @param size the font size
+ *
+ * @return the encoded font description
+ */
+ static String encodeFont(String name, int style, int size)
+ {
+ StringBuilder key = new StringBuilder();
+ key.append(validName(name));
+ key.append('.');
+ switch (style)
+ {
+ case Font.BOLD:
+ key.append("bold");
+ break;
+ case Font.ITALIC:
+ key.append("italic");
+ break;
+ case (Font.BOLD | Font.ITALIC):
+ key.append("bolditalic");
+ break;
+ case Font.PLAIN:
+ default:
+ key.append("plain");
+
+ }
+
+ String protoType = fontProperties.getProperty(key.toString());
+ int s = validSize(size);
+ return protoType.replaceFirst("%d", String.valueOf(s));
+ }
+
+ /**
+ * Checks the specified font name for a valid font name. If the font name
+ * is not known, then this returns 'sansserif' as fallback.
+ *
+ * @param name the font name to check
+ *
+ * @return a valid font name
+ */
+ static String validName(String name)
+ {
+ String retVal;
+ if (name.equalsIgnoreCase("sansserif")
+ || name.equalsIgnoreCase("serif")
+ || name.equalsIgnoreCase("monospaced")
+ || name.equalsIgnoreCase("dialog")
+ || name.equalsIgnoreCase("dialoginput"))
+ {
+ retVal = name.toLowerCase();
+ }
+ else
+ {
+ retVal = "sansserif";
+ }
+ return retVal;
+ }
+
+ /**
+ * Translates an arbitrary point size to a size that is typically available
+ * on an X server. These are the sizes 8, 10, 12, 14, 18 and 24.
+ *
+ * @param size the queried size
+ * @return the real available size
+ */
+ private static final int validSize(int size)
+ {
+ int val;
+ if (size <= 9)
+ val = 8;
+ else if (size <= 11)
+ val = 10;
+ else if (size <= 13)
+ val = 12;
+ else if (size <= 17)
+ val = 14;
+ else if (size <= 23)
+ val = 18;
+ else
+ val = 24;
+ return val;
+ }
+
+ /**
+ * Returns the X Font reference. This lazily loads the font when first
+ * requested.
+ *
+ * @return the X Font reference
+ */
+ gnu.x11.Font getXFont()
+ {
+ if (xfont == null)
+ {
+ init(name, style, size);
+ }
+ return xfont;
+ }
+}
diff --git a/gnu/java/awt/peer/x/XFramePeer.java b/gnu/java/awt/peer/x/XFramePeer.java
index 74e47bc28..7424dc671 100644
--- a/gnu/java/awt/peer/x/XFramePeer.java
+++ b/gnu/java/awt/peer/x/XFramePeer.java
@@ -65,6 +65,7 @@ public class XFramePeer
XFramePeer(Frame f)
{
super(f);
+ setTitle(f.getTitle());
}
public void setIconImage(Image image)
@@ -87,8 +88,7 @@ public class XFramePeer
public void setTitle(String title)
{
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
+ xwindow.set_wm_name (title);
}
public int getState()
diff --git a/gnu/java/awt/peer/x/XGraphics2D.java b/gnu/java/awt/peer/x/XGraphics2D.java
index 73e780cc5..e64653e1d 100644
--- a/gnu/java/awt/peer/x/XGraphics2D.java
+++ b/gnu/java/awt/peer/x/XGraphics2D.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.awt.peer.x;
import java.awt.Color;
+import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
@@ -45,11 +46,16 @@ import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
+import java.awt.Transparency;
import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
import java.awt.image.ImageObserver;
import java.awt.image.Raster;
+import java.awt.peer.FontPeer;
import java.util.HashMap;
+import java.util.WeakHashMap;
import gnu.java.awt.java2d.AbstractGraphics2D;
import gnu.java.awt.java2d.ScanlineCoverage;
@@ -92,11 +98,19 @@ public class XGraphics2D
//setClip(new Rectangle(0, 0, xdrawable.width, xdrawable.height));
}
+ @Override
protected void rawDrawLine(int x0, int y0, int x1, int y1)
{
xdrawable.segment(xgc, x0, y0, x1, y1);
}
+ @Override
+ protected void rawDrawRect(int x, int y, int w, int h)
+ {
+ xdrawable.rectangle(xgc, x, y, w, h, false);
+ }
+
+ @Override
protected void rawFillRect(int x, int y, int w, int h)
{
xdrawable.rectangle(xgc, x, y, w, h, true);
@@ -217,55 +231,65 @@ public class XGraphics2D
}
}
+ @Override
public void renderScanline(int y, ScanlineCoverage c)
{
+ if (y >= xdrawable.height)
+ return;
+
+ // TODO: Handle Composite and Paint.
ScanlineCoverage.Iterator iter = c.iterate();
- float coverageAlpha = 0;
+ int coverageAlpha = 0;
int maxCoverage = c.getMaxCoverage();
- Color old = getColor();
- Color col = getColor();
- if (col == null)
- col = Color.BLACK;
while (iter.hasNext())
{
ScanlineCoverage.Range range = iter.next();
- // TODO: Dumb implementation for testing.
+
coverageAlpha = range.getCoverage();
- if (coverageAlpha > 0)
+ int x0 = range.getXPos();
+ int l = range.getLength();
+ if (coverageAlpha == c.getMaxCoverage())
{
- int red = col.getRed();
- int green = col.getGreen();
- int blue = col.getBlue();
- if (coverageAlpha < c.getMaxCoverage())
+ // Simply paint the current color over the existing pixels.
+ xdrawable.fill_rectangle(xgc, x0, y, l, 1);
+ }
+ else if (coverageAlpha > 0)
+ {
+ // Composite the current color with the existing pixels.
+ int x1 = x0 + l;
+ x0 = Math.min(Math.max(0, x0), xdrawable.width - 1);
+ x1 = Math.min(Math.max(0, x1), xdrawable.width - 1);
+ if ((x1 - x0) < 1)
+ continue;
+ l = x1 - x0;
+ gnu.x11.image.ZPixmap existing = (ZPixmap)
+ xdrawable.image(x0, y, l, 1, 0xFFFFFFFF,
+ gnu.x11.image.Image.Format.ZPIXMAP);
+ for (int x = 0; x < l; x++)
{
- float alpha = coverageAlpha / maxCoverage;
- red = 255 - (int) ((255 - red) * alpha);
- green = 255 - (int) ((255 - green) * alpha);
- blue = 255 - (int) ((255 - blue) * alpha);
+ Color col = getColor();
+ if (col == null)
+ {
+ col = Color.BLACK;
+ }
+ int red = col.getRed();
+ int green = col.getGreen();
+ int blue = col.getBlue();
+ int redOut = existing.get_red(x, 0);
+ int greenOut = existing.get_green(x, 0);
+ int blueOut = existing.get_blue(x, 0);
+ int outAlpha = maxCoverage - coverageAlpha;
+ redOut = redOut * outAlpha + red * coverageAlpha;
+ redOut = redOut / maxCoverage;
+ greenOut = greenOut * outAlpha + green * coverageAlpha;
+ greenOut = greenOut / maxCoverage;
+ blueOut = blueOut * outAlpha + blue * coverageAlpha;
+ blueOut = blueOut / maxCoverage;
+ existing.set(x, 0, redOut, greenOut, blueOut);
}
- xgc.set_foreground(red << 16 | green << 8 | blue);
- int x0 = range.getXPos();
- int l = range.getLength();
- xdrawable.fill_rectangle(xgc, x0, y, l, 1);
+ xdrawable.put_image(xgc, existing, x0, y);
}
}
- if (old != null)
- xgc.set_foreground(old.getRGB());
- }
-
- protected void fillScanline(int x0, int x1, int y)
- {
- xdrawable.segment(xgc, x0, y, x1, y);
- }
-
- protected void fillScanlineAA(int x0, int x1, int y, int alpha)
- {
- //System.err.println("fillScanlineAA: " + x0 + ", " + x1 + ", " + y + ", " + alpha);
- // FIXME: This is for testing only.
- Color c = getColor();
- setColor(new Color(255-alpha, 255-alpha, 255-alpha));
- xdrawable.segment(xgc, x0, y, x1, y);
- setColor(c);
}
protected void init()
@@ -278,6 +302,7 @@ public class XGraphics2D
super.setPaint(p);
if (p instanceof Color)
{
+ // TODO: Optimize for different standard bit-depths.
Color c = (Color) p;
XToolkit tk = (XToolkit) Toolkit.getDefaultToolkit();
HashMap colorMap = tk.colorMap;
@@ -302,6 +327,8 @@ public class XGraphics2D
}
}
+ private static WeakHashMap<Image,ZPixmap> imageCache = new WeakHashMap<Image,ZPixmap>();
+
protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs)
{
boolean ret;
@@ -319,6 +346,85 @@ public class XGraphics2D
pvi.getHeight(obs), x, y);
ret = true;
}
+ else if (image instanceof BufferedImage)
+ {
+ BufferedImage bi = (BufferedImage) image;
+ DataBuffer db = bi.getRaster().getDataBuffer();
+ if (db instanceof ZPixmapDataBuffer)
+ {
+ ZPixmapDataBuffer zpmdb = (ZPixmapDataBuffer) db;
+ ZPixmap zpixmap = zpmdb.getZPixmap();
+ xdrawable.put_image(xgc, zpixmap, x, y);
+ ret = true;
+ }
+ else
+ {
+ int transparency = bi.getTransparency();
+ int w = bi.getWidth();
+ int h = bi.getHeight();
+ if (imageCache.containsKey(image))
+ {
+ ZPixmap zpixmap = imageCache.get(image);
+ xdrawable.put_image(xgc, zpixmap, x, y);
+ }
+ else if (transparency == Transparency.OPAQUE)
+ {
+ XGraphicsDevice gd = XToolkit.getDefaultDevice();
+ ZPixmap zpixmap = new ZPixmap(gd.getDisplay(), w, h);
+ for (int yy = 0; yy < h; yy++)
+ {
+ for (int xx = 0; xx < w; xx++)
+ {
+ int rgb = bi.getRGB(xx, yy);
+ zpixmap.set(xx, yy, rgb);
+ }
+ }
+ xdrawable.put_image(xgc, zpixmap, x, y);
+ imageCache.put(image, zpixmap);
+ } else {
+ ZPixmap zpixmap = (ZPixmap) xdrawable.image(x, y, w, h,
+ 0xffffffff,
+ gnu.x11.image.Image.Format.ZPIXMAP);
+ for (int yy = 0; yy < h; yy++)
+ {
+ for (int xx = 0; xx < w; xx++)
+ {
+ int rgb = bi.getRGB(xx, yy);
+ int alpha = 0xff & (rgb >> 24);
+ if (alpha == 0)
+ {
+ // Completely translucent.
+ rgb = zpixmap.get_red(xx, yy) << 16
+ | zpixmap.get_green(xx, yy) << 8
+ | zpixmap.get_blue(xx, yy);
+ }
+ else if (alpha < 255)
+ {
+ // Composite pixels.
+ int red = 0xff & (rgb >> 16);
+ red = red * alpha
+ + (255 - alpha) * zpixmap.get_red(xx, yy);
+ red = red / 255;
+ int green = 0xff & (rgb >> 8);
+ green = green * alpha
+ + (255 - alpha) * zpixmap.get_green(xx, yy);
+ green = green / 255;
+ int blue = 0xff & rgb;
+ blue = blue * alpha
+ + (255 - alpha) * zpixmap.get_blue(xx, yy);
+ blue = blue / 255;
+ }
+ // else keep rgb value from source image.
+
+ zpixmap.set(xx, yy, rgb);
+ }
+ }
+ xdrawable.put_image(xgc, zpixmap, x, y);
+ imageCache.put(image, zpixmap);
+ }
+ ret = true;
+ }
+ }
else
{
ret = super.rawDrawImage(image, x, y, obs);
@@ -326,6 +432,30 @@ public class XGraphics2D
return ret;
}
+ public void setFont(Font f)
+ {
+ super.setFont(f);
+ FontPeer p = getFont().getPeer();
+ if (p instanceof XFontPeer)
+ {
+ XFontPeer xFontPeer = (XFontPeer) p;
+ xgc.set_font(xFontPeer.getXFont());
+ }
+ }
+ public void drawString(String s, int x, int y)
+ {
+ FontPeer p = getFont().getPeer();
+ if (p instanceof XFontPeer)
+ {
+ int tx = (int) transform.getTranslateX();
+ int ty = (int) transform.getTranslateY();
+ xdrawable.text(xgc, x + tx, y + ty, s);
+ }
+ else
+ {
+ super.drawString(s, x, y);
+ }
+ }
}
diff --git a/gnu/java/awt/peer/x/XGraphicsConfiguration.java b/gnu/java/awt/peer/x/XGraphicsConfiguration.java
index 11a9c9694..85f72a4ef 100644
--- a/gnu/java/awt/peer/x/XGraphicsConfiguration.java
+++ b/gnu/java/awt/peer/x/XGraphicsConfiguration.java
@@ -37,6 +37,10 @@ exception statement from your version. */
package gnu.java.awt.peer.x;
+import gnu.x11.Display;
+import gnu.x11.Screen;
+
+import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.Point;
@@ -158,4 +162,38 @@ public class XGraphicsConfiguration
throw new UnsupportedOperationException("Not yet implemented.");
}
+ /**
+ * Determines the size of the primary screen.
+ *
+ * @return the size of the primary screen
+ */
+ Dimension getSize()
+ {
+ // TODO: A GraphicsConfiguration should correspond to a Screen instance.
+ Display d = device.getDisplay();
+ Screen screen = d.default_screen;
+ int w = screen.width;
+ int h = screen.height;
+ return new Dimension(w, h);
+ }
+
+ /**
+ * Determines the resolution of the primary screen in pixel-per-inch.
+ *
+ * @returnthe resolution of the primary screen in pixel-per-inch
+ */
+ int getResolution()
+ {
+ Display d = device.getDisplay();
+ Screen screen = d.default_screen;
+ int w = screen.width * 254;
+ int h = screen.height * 254;
+ int wmm = screen.width_in_mm * 10;
+ int hmm = screen.height_in_mm * 10;
+ int xdpi = w / wmm;
+ int ydpi = h / hmm;
+ int dpi = (xdpi + ydpi) / 2;
+ return dpi;
+ }
+
}
diff --git a/gnu/java/awt/peer/x/XGraphicsEnvironment.java b/gnu/java/awt/peer/x/XGraphicsEnvironment.java
index 65383a6cb..8ec8d57bb 100644
--- a/gnu/java/awt/peer/x/XGraphicsEnvironment.java
+++ b/gnu/java/awt/peer/x/XGraphicsEnvironment.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.awt.peer.x;
+import gnu.java.awt.font.OpenTypeFontPeer;
import gnu.java.awt.java2d.RasterGraphics;
import gnu.x11.Display;
@@ -189,14 +190,14 @@ public class XGraphicsEnvironment
public String[] getAvailableFontFamilyNames()
{
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
+ return getAvailableFontFamilyNames(Locale.getDefault());
}
public String[] getAvailableFontFamilyNames(Locale l)
{
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
+ // TODO: This doesn't work when we are using X fonts.
+ // Fix this.
+ return OpenTypeFontPeer.getAvailableFontFamilyNames(l);
}
}
diff --git a/gnu/java/awt/peer/x/XToolkit.java b/gnu/java/awt/peer/x/XToolkit.java
index 08186326f..000cb9404 100644
--- a/gnu/java/awt/peer/x/XToolkit.java
+++ b/gnu/java/awt/peer/x/XToolkit.java
@@ -51,6 +51,7 @@ import java.awt.FileDialog;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
@@ -117,6 +118,7 @@ import javax.imageio.ImageIO;
import gnu.classpath.SystemProperties;
import gnu.java.awt.ClasspathToolkit;
import gnu.java.awt.EmbeddedWindow;
+import gnu.java.awt.font.OpenTypeFontPeer;
import gnu.java.awt.peer.ClasspathFontPeer;
import gnu.java.awt.peer.EmbeddedWindowPeer;
import gnu.java.awt.peer.swing.SwingCanvasPeer;
@@ -155,7 +157,8 @@ public class XToolkit
/**
* The cached fonts.
*/
- private WeakHashMap fontCache = new WeakHashMap();
+ private WeakHashMap<String,ClasspathFontPeer> fontCache =
+ new WeakHashMap<String,ClasspathFontPeer>();
public XToolkit()
{
@@ -179,21 +182,32 @@ public class XToolkit
*/
public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs)
{
- String canonical = XFontPeer2.encodeFont(name, attrs);
ClasspathFontPeer font;
- if (!fontCache.containsKey(canonical))
+ if ("true".equals(System.getProperty("escherpeer.usexfonts")))
{
- String graphics2d =
- SystemProperties.getProperty("gnu.xawt.graphics2d");
- //if (graphics2d != null && graphics2d.equals("gl"))
- font = new XFontPeer2(name, attrs);
-// else
-// font = new XFontPeer(name, attrs);
- fontCache.put(canonical, font);
+ String canonical = XFontPeer.encodeFont(name, attrs);
+ if (!fontCache.containsKey(canonical))
+ {
+ font = new XFontPeer(name, attrs);
+ fontCache.put(canonical, font);
+ }
+ else
+ {
+ font = fontCache.get(canonical);
+ }
}
else
{
- font = (ClasspathFontPeer) fontCache.get(canonical);
+ String canonical = OpenTypeFontPeer.encodeFont(name, attrs);
+ if (!fontCache.containsKey(canonical))
+ {
+ font = new OpenTypeFontPeer(name, attrs);
+ fontCache.put(canonical, font);
+ }
+ else
+ {
+ font = fontCache.get(canonical);
+ }
}
return font;
}
@@ -338,14 +352,22 @@ public class XToolkit
public Dimension getScreenSize()
{
- // FIXME: This is only a hack to get some apps working.
- return new Dimension(1024, 768);
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = ge.getDefaultScreenDevice();
+ GraphicsConfiguration gc = gd.getDefaultConfiguration();
+ XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc;
+
+ return xgc.getSize();
}
public int getScreenResolution()
{
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = ge.getDefaultScreenDevice();
+ GraphicsConfiguration gc = gd.getDefaultConfiguration();
+ XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc;
+
+ return xgc.getResolution();
}
/**
@@ -363,8 +385,8 @@ public class XToolkit
public String[] getFontList()
{
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ return ge.getAvailableFontFamilyNames();
}
public FontMetrics getFontMetrics(Font name)
@@ -602,19 +624,17 @@ public class XToolkit
}
@Override
- public boolean isModalExclusionTypeSupported
- (Dialog.ModalExclusionType modalExclusionType)
+ public boolean isModalExclusionTypeSupported(ModalExclusionType modalExclusionType)
{
- // TODO: Implement properly.
+ // TODO Auto-generated method stub
return false;
}
@Override
- public boolean isModalityTypeSupported(Dialog.ModalityType modalityType)
+ public boolean isModalityTypeSupported(ModalityType modalityType)
{
- // TODO: Implement properly.
+ // TODO Auto-generated method stub
return false;
}
-
}
diff --git a/gnu/java/awt/peer/x/XWindowPeer.java b/gnu/java/awt/peer/x/XWindowPeer.java
index 10d1e9685..94ef8faa0 100644
--- a/gnu/java/awt/peer/x/XWindowPeer.java
+++ b/gnu/java/awt/peer/x/XWindowPeer.java
@@ -39,9 +39,11 @@ exception statement from your version. */
package gnu.java.awt.peer.x;
import java.awt.Component;
+import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
+import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
@@ -54,9 +56,11 @@ import java.awt.event.PaintEvent;
import java.awt.event.WindowEvent;
import java.awt.image.VolatileImage;
+import gnu.x11.Atom;
import gnu.x11.Window;
import gnu.x11.event.Event;
+import gnu.java.awt.font.OpenTypeFontPeer;
import gnu.java.awt.peer.swing.SwingWindowPeer;
public class XWindowPeer
@@ -84,7 +88,12 @@ public class XWindowPeer
/**
* The X window.
*/
- private Window xwindow;
+ protected Window xwindow;
+
+ /**
+ * The frame insets. These get updated in {@link #show()}.
+ */
+ private Insets insets;
XWindowPeer(java.awt.Window window)
{
@@ -92,15 +101,47 @@ public class XWindowPeer
XGraphicsDevice dev = XToolkit.getDefaultDevice();
// TODO: Maybe initialize lazily in show().
+ Window.Attributes atts = new Window.Attributes();
// FIXME: Howto generate a Window without decorations?
int x = Math.max(window.getX(), 0);
int y = Math.max(window.getY(), 0);
int w = Math.max(window.getWidth(), 1);
int h = Math.max(window.getHeight(), 1);
- xwindow = new Window(dev.getDisplay().default_root, x, y, w, h);
- xwindow.create();
+ xwindow = new Window(dev.getDisplay().default_root, x, y, w, h, 0, atts);
xwindow.select_input(standardSelect);
dev.getEventPump().registerWindow(xwindow, window);
+
+ boolean undecorated;
+ if (awtComponent instanceof Frame)
+ {
+ Frame f = (Frame) awtComponent;
+ undecorated = f.isUndecorated();
+ }
+ else if (awtComponent instanceof Dialog)
+ {
+ Dialog d = (Dialog) awtComponent;
+ undecorated = d.isUndecorated();
+ }
+ else
+ {
+ undecorated = true;
+ }
+ if (undecorated)
+ {
+ // First try the Motif implementation of undecorated frames. This
+ // is semantically closest and supported by all major window
+ // managers.
+ // TODO: At the time of writing this, there's no freedesktop.org
+ // standard extension that matches the required semantic. Maybe
+ // undecorated frames are added in the future, if so, then use these.
+ Atom at = Atom.intern(dev.getDisplay(), "_MOTIF_WM_HINTS");
+ if (at != null)
+ {
+ xwindow.change_property(Window.REPLACE, at, at, 32,
+ new int[]{1 << 1, 0, 0, 0, 0}, 0, 5);
+ }
+ }
+ insets = new Insets(0, 0, 0, 0);
}
public void toBack()
@@ -139,7 +180,11 @@ public class XWindowPeer
*/
public Graphics getGraphics()
{
- return new XGraphics2D(xwindow);
+ XGraphics2D xg2d = new XGraphics2D(xwindow);
+ xg2d.setColor(awtComponent.getForeground());
+ xg2d.setBackground(awtComponent.getBackground());
+ xg2d.setFont(awtComponent.getFont());
+ return xg2d;
}
public Image createImage(int w, int h)
@@ -164,16 +209,11 @@ public class XWindowPeer
*/
public void show()
{
-// // Prevent ResizeRedirect events.
-// //xwindow.select_input(noResizeRedirectSelect);
-// Window.Attributes atts = new Window.Attributes();
-// atts.set_override_redirect(true);
-// xwindow.change_attributes(atts);
-
// Prevent ResizeRedirect events.
//xwindow.select_input(Event.NO_EVENT_MASK);
//xwindow.select_input(noResizeRedirectSelect);
+ XGraphicsDevice dev = XToolkit.getDefaultDevice();
xwindow.map();
EventQueue eq = XToolkit.getDefaultToolkit().getSystemEventQueue();
java.awt.Window w = (java.awt.Window) super.awtComponent;
@@ -188,6 +228,20 @@ public class XWindowPeer
// // Reset input selection.
// atts.set_override_redirect(false);
// xwindow.change_attributes(atts);
+
+ // Determine the frame insets.
+ Atom atom = (Atom) Atom.intern(dev.getDisplay(), "_NET_FRAME_EXTENTS");
+ Window.Property p = xwindow.get_property(false, atom, Atom.CARDINAL, 0,
+ Window.MAX_WM_LENGTH);
+ if (p.format() != 0)
+ {
+ insets = new Insets(p.value(0), p.value(1), p.value(2), p.value(3));
+ Window.Changes ch = new Window.Changes();
+ ch.width(awtComponent.getWidth() - insets.left - insets.top);
+ ch.height(awtComponent.getHeight() - insets.top - insets.bottom);
+ xwindow.configure(ch);
+ }
+
}
/**
@@ -214,40 +268,19 @@ public class XWindowPeer
*/
public void reshape(int x, int y, int width, int height)
{
- // Prevent ResizeRedirect events.
-// //xwindow.select_input(noResizeRedirectSelect);
-// Window.Attributes atts = new Window.Attributes();
-// atts.set_override_redirect(true);
-// xwindow.change_attributes(atts);
-
// Need to substract insets because AWT size is including insets,
- // and X size is excuding insets.
- Insets i = insets();
- xwindow.move_resize(x - i.left, y - i.right, width - i.left - i.right,
- height - i.top - i.bottom);
-
- // Reset input selection.
-// atts = new Window.Attributes();
-// atts.set_override_redirect(false);
-// xwindow.change_attributes(atts);
+ // and X size is excluding insets.
+ if (! callback)
+ {
+ Insets i = insets;
+ xwindow.move_resize(x - i.left, y - i.right, width - i.left - i.right,
+ height - i.top - i.bottom);
+ }
}
public Insets insets()
{
- Insets i = new Insets(0, 0, 0, 0);
-// Window.GeometryReply g = xwindow.geometry();
-// int b = g.border_width();
-// Insets i = new Insets(b, b, b, b);
-// Window.WMSizeHints wmSize = xwindow.wm_normal_hints();
-// if (wmSize != null)
-// {
-// i.left = wmSize.x() - g.x();
-// i.right = wmSize.width() - g.width() - i.left ;
-// i.top = wmSize.y() - g.y();
-// i.bottom = wmSize.height() - g.height() - i.top;
-// }
-// System.err.println("insets: " + i);
- return i;
+ return (Insets) insets.clone();
}
/**
@@ -257,7 +290,8 @@ public class XWindowPeer
*/
public FontMetrics getFontMetrics(Font font)
{
- XFontPeer2 fontPeer = (XFontPeer2) font.getPeer();
+ // FIXME: Fix this for X fonts.
+ OpenTypeFontPeer fontPeer = (OpenTypeFontPeer) font.getPeer();
return fontPeer.getFontMetrics(font);
}
diff --git a/gnu/java/awt/peer/x/ZPixmapDataBuffer.java b/gnu/java/awt/peer/x/ZPixmapDataBuffer.java
index 8043c5b8f..cf40f4d69 100644
--- a/gnu/java/awt/peer/x/ZPixmapDataBuffer.java
+++ b/gnu/java/awt/peer/x/ZPixmapDataBuffer.java
@@ -59,4 +59,9 @@ class ZPixmapDataBuffer
zpixmap.set_data_element(i, (byte) val);
}
+ ZPixmap getZPixmap()
+ {
+ return zpixmap;
+ }
+
}
diff --git a/gnu/java/util/LRUCache.java b/gnu/java/util/LRUCache.java
new file mode 100644
index 000000000..784a442ab
--- /dev/null
+++ b/gnu/java/util/LRUCache.java
@@ -0,0 +1,77 @@
+/* LRUCache.java -- A LRU Cache implementation
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A least recently used cache, based on LinkedHashMap.
+ */
+public class LRUCache<K,V>
+ extends LinkedHashMap<K,V>
+{
+
+ /**
+ * The capacity of the cache.
+ */
+ private int capacity;
+
+ /**
+ * Creates a new LRUCache instance with the specified capacity.
+ *
+ * @param cap the capacity of the new cache
+ */
+ public LRUCache(int cap)
+ {
+ super();
+ capacity = cap;
+ }
+
+ /**
+ * Returns <code>true</code> when the oldest entry should be removed.
+ *
+ * @param eldest the entry about to be removed
+ *
+ * @return <code>true</code> when the oldest entry should be removed
+ */
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
+ {
+ return size() > capacity;
+ }
+}