Merged with mainline at revision 126347.
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / x / XFontPeer.java
blob8183fed0cd29ac5f620a15f69de2793facb01208
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)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.awt.peer.x;
41 import java.awt.AWTError;
42 import java.awt.Font;
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;
57 import java.util.Map;
58 import java.util.Properties;
60 import gnu.java.awt.peer.ClasspathFontPeer;
61 import gnu.x11.Display;
62 import gnu.x11.Fontable;
64 /**
65 * The bridge from AWT to X fonts.
67 * @author Roman Kennke (kennke@aicas.com)
69 public class XFontPeer
70 extends ClasspathFontPeer
73 /**
74 * The font mapping as specified in the file fonts.properties.
76 private static Properties fontProperties;
77 static
79 fontProperties = new Properties();
80 InputStream in = XFontPeer.class.getResourceAsStream("fonts.properties");
81 try
83 fontProperties.load(in);
85 catch (IOException e)
87 e.printStackTrace();
91 /**
92 * The FontMetrics implementation for XFontPeer.
94 private class XFontMetrics
95 extends FontMetrics
97 /**
98 * The ascent of the font.
99 */
100 int ascent;
103 * The descent of the font.
105 int descent;
108 * The maximum of the character advances.
110 private int maxAdvance;
113 * The internal leading.
115 int 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)
135 super(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);
145 else
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++)
163 charWidths[i] = 0;
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();
173 index++;
177 private void readCharWidthsNonLinear(Fontable.FontReply info)
179 // TODO: Implement.
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()
190 return ascent;
194 * Returns the descent of the font.
196 * @return the descent of the font
198 public int getDescent()
200 return descent;
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()
221 return leading;
225 * Returns the maximum advance for this font.
227 * @return the maximum advance for this font
229 public int getMaxAdvance()
231 return maxAdvance;
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)
243 int width;
244 if (c > charWidths.length)
245 width = charWidths['?'];
246 else
247 width = charWidths[c];
248 return width;
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)
262 int width = 0;
263 if (c.length > 0 && length > 0)
265 String s = new String(c, offset, length);
266 width = stringWidth(s);
268 return width;
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)
280 int width = 0;
281 if (s.length() > 0)
283 if (metricsCache.containsKey(s))
285 width = ((Integer) metricsCache.get(s)).intValue();
287 else
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);
307 return width;
312 * The LineMetrics implementation for the XFontPeer.
314 private class XLineMetrics
315 extends LineMetrics
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??
400 * The X font.
402 private gnu.x11.Font xfont;
404 private String name;
406 private int style;
408 private int size;
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);
425 this.name = name;
426 this.style = style;
427 this.size = size;
431 * Creates a new XFontPeer for the specified font name and style
432 * attributes.
434 * @param name the font name
435 * @param atts the font attributes
437 public XFontPeer(String name, Map atts)
439 super(name, atts);
440 String family = name;
441 if (family == null || family.equals(""))
442 family = (String) atts.get(TextAttribute.FAMILY);
443 if (family == null)
444 family = "SansSerif";
446 int size = 12;
447 Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
448 if (sizeFl != null)
449 size = sizeFl.intValue();
451 int style = 0;
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)
460 style |= Font.BOLD;
462 this.name = name;
463 this.style = style;
464 this.size = size;
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);
483 if (XToolkit.DEBUG)
484 System.err.println("XLFD font description: " + fontDescr);
485 xfont = new gnu.x11.Font(display, fontDescr);
487 else
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,
549 int[] glyphCodes)
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,
557 int flags)
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);
577 return fontMetrics;
581 * Frees the font in the X server.
583 protected void finalize()
585 if (xfont != null)
586 xfont.close();
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);
630 if (family == null)
631 family = "SansSerif";
633 int size = 12;
634 Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
635 if (sizeFl != null)
636 size = sizeFl.intValue();
638 int style = 0;
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)
647 style |= Font.BOLD;
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));
671 key.append('.');
672 switch (style)
674 case Font.BOLD:
675 key.append("bold");
676 break;
677 case Font.ITALIC:
678 key.append("italic");
679 break;
680 case (Font.BOLD | Font.ITALIC):
681 key.append("bolditalic");
682 break;
683 case Font.PLAIN:
684 default:
685 key.append("plain");
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)
704 String retVal;
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();
713 else
715 retVal = "sansserif";
717 return retVal;
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)
729 int val;
730 if (size <= 9)
731 val = 8;
732 else if (size <= 11)
733 val = 10;
734 else if (size <= 13)
735 val = 12;
736 else if (size <= 17)
737 val = 14;
738 else if (size <= 23)
739 val = 18;
740 else
741 val = 24;
742 return val;
746 * Returns the X Font reference. This lazily loads the font when first
747 * requested.
749 * @return the X Font reference
751 gnu.x11.Font getXFont()
753 if (xfont == null)
755 init(name, style, size);
757 return xfont;