1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59:
60: import ;
61: import ;
62: import ;
63:
64:
69: public class XFontPeer
70: extends ClasspathFontPeer
71: {
72:
73:
76: private static Properties fontProperties;
77: static
78: {
79: fontProperties = new Properties();
80: InputStream in = XFontPeer.class.getResourceAsStream("fonts.properties");
81: try
82: {
83: fontProperties.load(in);
84: }
85: catch (IOException e)
86: {
87: e.printStackTrace();
88: }
89: }
90:
91:
94: private class XFontMetrics
95: extends FontMetrics
96: {
97:
100: int ascent;
101:
102:
105: int descent;
106:
107:
110: private int maxAdvance;
111:
112:
115: int leading;
116:
117:
121: private HashMap metricsCache;
122:
123:
126: private int[] charWidths;
127:
128:
133: protected XFontMetrics(Font font)
134: {
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;
142:
143: if (info.min_byte1() == 0 && info.max_byte1() == 0)
144: readCharWidthsLinear(info);
145: else
146: readCharWidthsNonLinear(info);
147: }
148:
149:
155: private void readCharWidthsLinear(Fontable.FontReply info)
156: {
157: int startIndex = info.min_char_or_byte2();
158: int endIndex = info.max_char_or_byte2();
159: charWidths = new int[endIndex + 1];
160:
161: for (int i = 0; i < startIndex; i++)
162: {
163: charWidths[i] = 0;
164: }
165:
166: int index = startIndex;
167: Iterator charInfos = info.char_infos().iterator();
168: while (charInfos.hasNext())
169: {
170: Fontable.FontReply.CharInfo charInfo =
171: (Fontable.FontReply.CharInfo) charInfos.next();
172: charWidths[index] = charInfo.character_width();
173: index++;
174: }
175: }
176:
177: private void readCharWidthsNonLinear(Fontable.FontReply info)
178: {
179:
180: throw new UnsupportedOperationException("Not yet implemented");
181: }
182:
183:
188: public int getAscent()
189: {
190: return ascent;
191: }
192:
193:
198: public int getDescent()
199: {
200: return descent;
201: }
202:
203:
209: public int getHeight()
210: {
211: return ascent + descent;
212: }
213:
214:
219: public int getLeading()
220: {
221: return leading;
222: }
223:
224:
229: public int getMaxAdvance()
230: {
231: return maxAdvance;
232: }
233:
234:
241: public int charWidth(char c)
242: {
243: int width;
244: if (c > charWidths.length)
245: width = charWidths['?'];
246: else
247: width = charWidths[c];
248: return width;
249: }
250:
251:
260: public int charsWidth(char[] c, int offset, int length)
261: {
262: int width = 0;
263: if (c.length > 0 && length > 0)
264: {
265: String s = new String(c, offset, length);
266: width = stringWidth(s);
267: }
268: return width;
269: }
270:
271:
278: public int stringWidth(String s)
279: {
280: int width = 0;
281: if (s.length() > 0)
282: {
283: if (metricsCache.containsKey(s))
284: {
285: width = ((Integer) metricsCache.get(s)).intValue();
286: }
287: else
288: {
289: Fontable.TextExtentReply extents = getXFont().text_extent(s);
290:
300: width = extents.overall_width();
301:
302: metricsCache.put(s, new Integer(width));
303: }
304: }
305:
306:
307: return width;
308: }
309: }
310:
311:
314: private class XLineMetrics
315: extends LineMetrics
316: {
317:
318:
323: public float getAscent()
324: {
325: return fontMetrics.ascent;
326: }
327:
328: public int getBaselineIndex()
329: {
330:
331: throw new UnsupportedOperationException();
332: }
333:
334: public float[] getBaselineOffsets()
335: {
336:
337: throw new UnsupportedOperationException();
338: }
339:
340:
345: public float getDescent()
346: {
347: return fontMetrics.descent;
348: }
349:
350:
356: public float getHeight()
357: {
358: return fontMetrics.ascent + fontMetrics.descent;
359: }
360:
361:
366: public float getLeading()
367: {
368: return fontMetrics.leading;
369: }
370:
371: public int getNumChars()
372: {
373:
374: throw new UnsupportedOperationException();
375: }
376:
377: public float getStrikethroughOffset()
378: {
379: return 0.F;
380: }
381:
382: public float getStrikethroughThickness()
383: {
384: return 1.F;
385: }
386:
387: public float getUnderlineOffset()
388: {
389: return 0.F;
390: }
391:
392: public float getUnderlineThickness()
393: {
394: return 1.F;
395: }
396:
397: }
398:
399:
402: private gnu.x11.Font xfont;
403:
404: private String name;
405:
406: private int style;
407:
408: private int size;
409:
410:
413: XFontMetrics fontMetrics;
414:
415:
422: public XFontPeer(String name, int style, int size)
423: {
424: super(name, style, size);
425: this.name = name;
426: this.style = style;
427: this.size = size;
428: }
429:
430:
437: public XFontPeer(String name, Map atts)
438: {
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";
445:
446: int size = 12;
447: Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
448: if (sizeFl != null)
449: size = sizeFl.intValue();
450:
451: int style = 0;
452:
453: Float posture = (Float) atts.get(TextAttribute.POSTURE);
454: if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
455: style |= Font.ITALIC;
456:
457:
458: Float weight = (Float) atts.get(TextAttribute.WEIGHT);
459: if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
460: style |= Font.BOLD;
461:
462: this.name = name;
463: this.style = style;
464: this.size = size;
465: }
466:
467:
475: private void init(String name, int style, int size)
476: {
477: GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
478: GraphicsDevice dev = env.getDefaultScreenDevice();
479: if (dev instanceof XGraphicsDevice)
480: {
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);
486: }
487: else
488: {
489: throw new AWTError("Local GraphicsEnvironment is not XWindowGraphicsEnvironment");
490: }
491: }
492:
493: public boolean canDisplay(Font font, char c)
494: {
495:
496: throw new UnsupportedOperationException("Not yet implemented.");
497: }
498:
499: public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit)
500: {
501:
502: throw new UnsupportedOperationException("Not yet implemented.");
503: }
504:
505: public String getSubFamilyName(Font font, Locale locale)
506: {
507:
508: throw new UnsupportedOperationException("Not yet implemented.");
509: }
510:
511: public String getPostScriptName(Font font)
512: {
513:
514: throw new UnsupportedOperationException("Not yet implemented.");
515: }
516:
517: public int getNumGlyphs(Font font)
518: {
519:
520: throw new UnsupportedOperationException("Not yet implemented.");
521: }
522:
523: public int getMissingGlyphCode(Font font)
524: {
525:
526: throw new UnsupportedOperationException("Not yet implemented.");
527: }
528:
529: public byte getBaselineFor(Font font, char c)
530: {
531:
532: throw new UnsupportedOperationException("Not yet implemented.");
533: }
534:
535: public String getGlyphName(Font font, int glyphIndex)
536: {
537:
538: throw new UnsupportedOperationException("Not yet implemented.");
539: }
540:
541: public GlyphVector createGlyphVector(Font font, FontRenderContext frc,
542: CharacterIterator ci)
543: {
544:
545: throw new UnsupportedOperationException("Not yet implemented.");
546: }
547:
548: public GlyphVector createGlyphVector(Font font, FontRenderContext ctx,
549: int[] glyphCodes)
550: {
551:
552: throw new UnsupportedOperationException("Not yet implemented.");
553: }
554:
555: public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc,
556: char[] chars, int start, int limit,
557: int flags)
558: {
559:
560: throw new UnsupportedOperationException("Not yet implemented.");
561: }
562:
563:
570: public FontMetrics getFontMetrics(Font font)
571: {
572: if (font.getPeer() != this)
573: throw new AWTError("The specified font has a different peer than this");
574:
575: if (fontMetrics == null)
576: fontMetrics = new XFontMetrics(font);
577: return fontMetrics;
578: }
579:
580:
583: protected void finalize()
584: {
585: if (xfont != null)
586: xfont.close();
587: }
588:
589: public boolean hasUniformLineMetrics(Font font)
590: {
591:
592: throw new UnsupportedOperationException("Not yet implemented.");
593: }
594:
595:
599: public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin,
600: int limit, FontRenderContext rc)
601: {
602: return new XLineMetrics();
603: }
604:
605: public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc)
606: {
607:
608: throw new UnsupportedOperationException("Not yet implemented.");
609: }
610:
611: public Rectangle2D getStringBounds(Font font, CharacterIterator ci,
612: int begin, int limit, FontRenderContext frc)
613: {
614:
615: throw new UnsupportedOperationException("Not yet implemented.");
616: }
617:
618:
632: static String encodeFont(String name, Map atts)
633: {
634: String family = name;
635: if (family == null || family.equals(""))
636: family = (String) atts.get(TextAttribute.FAMILY);
637: if (family == null)
638: family = "SansSerif";
639:
640: int size = 12;
641: Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
642: if (sizeFl != null)
643: size = sizeFl.intValue();
644:
645: int style = 0;
646:
647: Float posture = (Float) atts.get(TextAttribute.POSTURE);
648: if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
649: style |= Font.ITALIC;
650:
651:
652: Float weight = (Float) atts.get(TextAttribute.WEIGHT);
653: if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
654: style |= Font.BOLD;
655:
656: return encodeFont(name, style, size);
657: }
658:
659:
674: static String encodeFont(String name, int style, int size)
675: {
676: StringBuilder key = new StringBuilder();
677: key.append(validName(name));
678: key.append('.');
679: switch (style)
680: {
681: case Font.BOLD:
682: key.append("bold");
683: break;
684: case Font.ITALIC:
685: key.append("italic");
686: break;
687: case (Font.BOLD | Font.ITALIC):
688: key.append("bolditalic");
689: break;
690: case Font.PLAIN:
691: default:
692: key.append("plain");
693:
694: }
695:
696: String protoType = fontProperties.getProperty(key.toString());
697: int s = validSize(size);
698: return protoType.replaceFirst("%d", String.valueOf(s * 10));
699: }
700:
701:
709: static String validName(String name)
710: {
711: String retVal;
712: if (name.equalsIgnoreCase("sansserif")
713: || name.equalsIgnoreCase("serif")
714: || name.equalsIgnoreCase("monospaced")
715: || name.equalsIgnoreCase("dialog")
716: || name.equalsIgnoreCase("dialoginput"))
717: {
718: retVal = name.toLowerCase();
719: }
720: else
721: {
722: retVal = "sansserif";
723: }
724: return retVal;
725: }
726:
727:
734: private static final int validSize(int size)
735: {
736: int val;
737: if (size <= 9)
738: val = 8;
739: else if (size <= 11)
740: val = 10;
741: else if (size <= 13)
742: val = 12;
743: else if (size <= 17)
744: val = 14;
745: else if (size <= 23)
746: val = 18;
747: else
748: val = 24;
749: return val;
750: }
751:
752:
758: gnu.x11.Font getXFont()
759: {
760: if (xfont == null)
761: {
762: init(name, style, size);
763: }
764: return xfont;
765: }
766: }