1 /* XFontPeer.java -- The font peer for X
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.awt.peer.x;
41 import java.awt.AWTError;
43 import java.awt.FontMetrics;
44 import java.awt.GraphicsDevice;
45 import java.awt.GraphicsEnvironment;
46 import java.awt.font.FontRenderContext;
47 import java.awt.font.GlyphVector;
48 import java.awt.font.LineMetrics;
49 import java.awt.font.TextAttribute;
50 import java.awt.geom.Rectangle2D;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.text.CharacterIterator;
54 import java.util.HashMap;
55 import java.util.Iterator;
56 import java.util.Locale;
58 import java.util.Properties;
60 import gnu.java.awt.peer.ClasspathFontPeer;
61 import gnu.x11.Display;
62 import gnu.x11.Fontable;
65 * The bridge from AWT to X fonts.
67 * @author Roman Kennke (kennke@aicas.com)
69 public class XFontPeer
70 extends ClasspathFontPeer
74 * The font mapping as specified in the file fonts.properties.
76 private static Properties fontProperties;
79 fontProperties = new Properties();
80 InputStream in = XFontPeer.class.getResourceAsStream("fonts.properties");
83 fontProperties.load(in);
92 * The FontMetrics implementation for XFontPeer.
94 private class XFontMetrics
98 * The ascent of the font.
103 * The descent of the font.
108 * The maximum of the character advances.
110 private int maxAdvance;
113 * The internal leading.
118 * Cached string metrics. This caches string metrics locally so that the
119 * server doesn't have to be asked each time.
121 private HashMap metricsCache;
124 * The widths of the characters indexed by the characters themselves.
126 private int[] charWidths;
129 * Creates a new XFontMetrics for the specified font.
131 * @param font the font
133 protected XFontMetrics(Font font)
136 metricsCache = new HashMap();
137 Fontable.FontReply info = getXFont().info();
138 ascent = info.font_ascent();
139 descent = info.font_descent();
140 maxAdvance = info.max_bounds().character_width();
141 leading = 0; // TODO: Not provided by X. Possible not needed.
143 if (info.min_byte1() == 0 && info.max_byte1() == 0)
144 readCharWidthsLinear(info);
146 readCharWidthsNonLinear(info);
150 * Reads the character widths when specified in a linear fashion. That is
151 * when the min-byte1 and max-byte2 fields are both zero in the X protocol.
153 * @param info the font info reply
155 private void readCharWidthsLinear(Fontable.FontReply info)
157 int startIndex = info.min_char_or_byte2();
158 int endIndex = info.max_char_or_byte2();
159 charWidths = new int[endIndex + 1];
160 // All the characters before startIndex are zero width.
161 for (int i = 0; i < startIndex; i++)
165 // All the other character info is fetched from the font info.
166 int index = startIndex;
167 Iterator charInfos = info.char_infos().iterator();
168 while (charInfos.hasNext())
170 Fontable.FontReply.CharInfo charInfo =
171 (Fontable.FontReply.CharInfo) charInfos.next();
172 charWidths[index] = charInfo.character_width();
177 private void readCharWidthsNonLinear(Fontable.FontReply info)
180 throw new UnsupportedOperationException("Not yet implemented");
184 * Returns the ascent of the font.
186 * @return the ascent of the font
188 public int getAscent()
194 * Returns the descent of the font.
196 * @return the descent of the font
198 public int getDescent()
204 * Returns the overall height of the font. This is the distance from
205 * baseline to baseline (usually ascent + descent + leading).
207 * @return the overall height of the font
209 public int getHeight()
211 return ascent + descent;
215 * Returns the leading of the font.
217 * @return the leading of the font
219 public int getLeading()
225 * Returns the maximum advance for this font.
227 * @return the maximum advance for this font
229 public int getMaxAdvance()
235 * Determines the width of the specified character <code>c</code>.
237 * @param c the character
239 * @return the width of the character
241 public int charWidth(char c)
244 if (c > charWidths.length)
245 width = charWidths['?'];
247 width = charWidths[c];
252 * Determines the overall width of the specified string.
254 * @param c the char buffer holding the string
255 * @param offset the starting offset of the string in the buffer
256 * @param length the number of characters in the string buffer
258 * @return the overall width of the specified string
260 public int charsWidth(char[] c, int offset, int length)
263 if (c.length > 0 && length > 0)
265 String s = new String(c, offset, length);
266 width = stringWidth(s);
272 * Determines the overall width of the specified string.
274 * @param s the string
276 * @return the overall width of the specified string
278 public int stringWidth(String s)
283 if (metricsCache.containsKey(s))
285 width = ((Integer) metricsCache.get(s)).intValue();
289 Fontable.TextExtentReply extents = getXFont().text_extent(s);
291 System.err.println("string: '" + s + "' : ");
292 System.err.println("ascent: " + extents.getAscent());
293 System.err.println("descent: " + extents.getDescent());
294 System.err.println("overall ascent: " + extents.getOverallAscent());
295 System.err.println("overall descent: " + extents.getOverallDescent());
296 System.err.println("overall width: " + extents.getOverallWidth());
297 System.err.println("overall left: " + extents.getOverallLeft());
298 System.err.println("overall right: " + extents.getOverallRight());
300 width = extents.overall_width(); // + extents.overall_left();
301 //System.err.println("String: " + s + ", width: " + width);
302 metricsCache.put(s, new Integer(width));
305 //System.err.print("stringWidth: '" + s + "': ");
306 //System.err.println(width);
312 * The LineMetrics implementation for the XFontPeer.
314 private class XLineMetrics
319 * Returns the ascent of the font.
321 * @return the ascent of the font
323 public float getAscent()
325 return fontMetrics.ascent;
328 public int getBaselineIndex()
330 // FIXME: Implement this.
331 throw new UnsupportedOperationException();
334 public float[] getBaselineOffsets()
336 // FIXME: Implement this.
337 throw new UnsupportedOperationException();
341 * Returns the descent of the font.
343 * @return the descent of the font
345 public float getDescent()
347 return fontMetrics.descent;
351 * Returns the overall height of the font. This is the distance from
352 * baseline to baseline (usually ascent + descent + leading).
354 * @return the overall height of the font
356 public float getHeight()
358 return fontMetrics.ascent + fontMetrics.descent;
362 * Returns the leading of the font.
364 * @return the leading of the font
366 public float getLeading()
368 return fontMetrics.leading;
371 public int getNumChars()
373 // FIXME: Implement this.
374 throw new UnsupportedOperationException();
377 public float getStrikethroughOffset()
379 return 0.F; // TODO: Provided by X??
382 public float getStrikethroughThickness()
384 return 1.F; // TODO: Provided by X??
387 public float getUnderlineOffset()
389 return 0.F; // TODO: Provided by X??
392 public float getUnderlineThickness()
394 return 1.F; // TODO: Provided by X??
402 private gnu.x11.Font xfont;
411 * The font metrics for this font.
413 XFontMetrics fontMetrics;
416 * Creates a new XFontPeer for the specified font name, style and size.
418 * @param name the font name
419 * @param style the font style (bold / italic / normal)
420 * @param size the size of the font
422 public XFontPeer(String name, int style, int size)
424 super(name, style, size);
431 * Creates a new XFontPeer for the specified font name and style
434 * @param name the font name
435 * @param atts the font attributes
437 public XFontPeer(String name, Map atts)
440 String family = name;
441 if (family == null || family.equals(""))
442 family = (String) atts.get(TextAttribute.FAMILY);
444 family = "SansSerif";
447 Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
449 size = sizeFl.intValue();
452 // Detect italic attribute.
453 Float posture = (Float) atts.get(TextAttribute.POSTURE);
454 if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
455 style |= Font.ITALIC;
457 // Detect bold attribute.
458 Float weight = (Float) atts.get(TextAttribute.WEIGHT);
459 if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
468 * Initializes the font peer with the specified attributes. This method is
469 * called from both constructors.
471 * @param name the font name
472 * @param style the font style
473 * @param size the font size
475 private void init(String name, int style, int size)
477 GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
478 GraphicsDevice dev = env.getDefaultScreenDevice();
479 if (dev instanceof XGraphicsDevice)
481 Display display = ((XGraphicsDevice) dev).getDisplay();
482 String fontDescr = encodeFont(name, style, size);
484 System.err.println("XLFD font description: " + fontDescr);
485 xfont = new gnu.x11.Font(display, fontDescr);
489 throw new AWTError("Local GraphicsEnvironment is not XWindowGraphicsEnvironment");
493 public boolean canDisplay(Font font, char c)
495 // TODO: Implement this.
496 throw new UnsupportedOperationException("Not yet implemented.");
499 public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit)
501 // TODO: Implement this.
502 throw new UnsupportedOperationException("Not yet implemented.");
505 public String getSubFamilyName(Font font, Locale locale)
507 // TODO: Implement this.
508 throw new UnsupportedOperationException("Not yet implemented.");
511 public String getPostScriptName(Font font)
513 // TODO: Implement this.
514 throw new UnsupportedOperationException("Not yet implemented.");
517 public int getNumGlyphs(Font font)
519 // TODO: Implement this.
520 throw new UnsupportedOperationException("Not yet implemented.");
523 public int getMissingGlyphCode(Font font)
525 // TODO: Implement this.
526 throw new UnsupportedOperationException("Not yet implemented.");
529 public byte getBaselineFor(Font font, char c)
531 // TODO: Implement this.
532 throw new UnsupportedOperationException("Not yet implemented.");
535 public String getGlyphName(Font font, int glyphIndex)
537 // TODO: Implement this.
538 throw new UnsupportedOperationException("Not yet implemented.");
541 public GlyphVector createGlyphVector(Font font, FontRenderContext frc,
542 CharacterIterator ci)
544 // TODO: Implement this.
545 throw new UnsupportedOperationException("Not yet implemented.");
548 public GlyphVector createGlyphVector(Font font, FontRenderContext ctx,
551 // TODO: Implement this.
552 throw new UnsupportedOperationException("Not yet implemented.");
555 public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc,
556 char[] chars, int start, int limit,
559 // TODO: Implement this.
560 throw new UnsupportedOperationException("Not yet implemented.");
564 * Returns the font metrics for the specified font.
566 * @param font the font for which to fetch the font metrics
568 * @return the font metrics for the specified font
570 public FontMetrics getFontMetrics(Font font)
572 if (font.getPeer() != this)
573 throw new AWTError("The specified font has a different peer than this");
575 if (fontMetrics == null)
576 fontMetrics = new XFontMetrics(font);
581 * Frees the font in the X server.
583 protected void finalize()
589 public boolean hasUniformLineMetrics(Font font)
591 // TODO: Implement this.
592 throw new UnsupportedOperationException("Not yet implemented.");
596 * Returns the line metrics for this font and the specified string and
597 * font render context.
599 public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin,
600 int limit, FontRenderContext rc)
602 return new XLineMetrics();
605 public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc)
607 // TODO: Implement this.
608 throw new UnsupportedOperationException("Not yet implemented.");
612 * Encodes a font name + style + size specification into a X logical font
613 * description (XLFD) as described here:
615 * http://www.meretrx.com/e93/docs/xlfd.html
617 * This is implemented to look up the font description in the
618 * fonts.properties of this package.
620 * @param name the font name
621 * @param atts the text attributes
623 * @return the encoded font description
625 static String encodeFont(String name, Map atts)
627 String family = name;
628 if (family == null || family.equals(""))
629 family = (String) atts.get(TextAttribute.FAMILY);
631 family = "SansSerif";
634 Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
636 size = sizeFl.intValue();
639 // Detect italic attribute.
640 Float posture = (Float) atts.get(TextAttribute.POSTURE);
641 if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
642 style |= Font.ITALIC;
644 // Detect bold attribute.
645 Float weight = (Float) atts.get(TextAttribute.WEIGHT);
646 if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
649 return encodeFont(name, style, size);
653 * Encodes a font name + style + size specification into a X logical font
654 * description (XLFD) as described here:
656 * http://www.meretrx.com/e93/docs/xlfd.html
658 * This is implemented to look up the font description in the
659 * fonts.properties of this package.
661 * @param name the font name
662 * @param style the font style
663 * @param size the font size
665 * @return the encoded font description
667 static String encodeFont(String name, int style, int size)
669 StringBuilder key = new StringBuilder();
670 key.append(validName(name));
678 key.append("italic");
680 case (Font.BOLD | Font.ITALIC):
681 key.append("bolditalic");
689 String protoType = fontProperties.getProperty(key.toString());
690 int s = validSize(size);
691 return protoType.replaceFirst("%d", String.valueOf(s * 10));
695 * Checks the specified font name for a valid font name. If the font name
696 * is not known, then this returns 'sansserif' as fallback.
698 * @param name the font name to check
700 * @return a valid font name
702 static String validName(String name)
705 if (name.equalsIgnoreCase("sansserif")
706 || name.equalsIgnoreCase("serif")
707 || name.equalsIgnoreCase("monospaced")
708 || name.equalsIgnoreCase("dialog")
709 || name.equalsIgnoreCase("dialoginput"))
711 retVal = name.toLowerCase();
715 retVal = "sansserif";
721 * Translates an arbitrary point size to a size that is typically available
722 * on an X server. These are the sizes 8, 10, 12, 14, 18 and 24.
724 * @param size the queried size
725 * @return the real available size
727 private static final int validSize(int size)
746 * Returns the X Font reference. This lazily loads the font when first
749 * @return the X Font reference
751 gnu.x11.Font getXFont()
755 init(name, style, size);