Source for gnu.java.awt.peer.x.XFontPeer2

   1: /* XFontPeer2.java -- A Java based TTF font peer for X
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   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.
  10: 
  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.
  15: 
  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.
  20: 
  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.
  25: 
  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. */
  37: 
  38: package gnu.java.awt.peer.x;
  39: 
  40: import java.awt.Font;
  41: import java.awt.FontMetrics;
  42: import java.awt.font.FontRenderContext;
  43: import java.awt.font.GlyphVector;
  44: import java.awt.font.LineMetrics;
  45: import java.awt.font.TextAttribute;
  46: import java.awt.geom.AffineTransform;
  47: import java.awt.geom.Point2D;
  48: import java.awt.geom.Rectangle2D;
  49: import java.io.File;
  50: import java.io.FileInputStream;
  51: import java.io.IOException;
  52: import java.io.InputStream;
  53: import java.nio.ByteBuffer;
  54: import java.nio.channels.FileChannel;
  55: import java.text.CharacterIterator;
  56: import java.text.StringCharacterIterator;
  57: import java.util.Locale;
  58: import java.util.Map;
  59: import java.util.Properties;
  60: 
  61: import gnu.java.awt.font.FontDelegate;
  62: import gnu.java.awt.font.FontFactory;
  63: import gnu.java.awt.peer.ClasspathFontPeer;
  64: 
  65: public class XFontPeer2
  66:   extends ClasspathFontPeer
  67: {
  68: 
  69:   /**
  70:    * The font mapping as specified in the file fonts.properties.
  71:    */
  72:   private static Properties fontProperties;
  73:   static
  74:   {
  75:     fontProperties = new Properties();
  76:     InputStream in = XFontPeer2.class.getResourceAsStream("fonts.properties");
  77:     try
  78:       {
  79:         fontProperties.load(in);
  80:       }
  81:     catch (IOException e)
  82:       {
  83:         e.printStackTrace();
  84:       }
  85:   }
  86: 
  87:   private class XLineMetrics
  88:     extends LineMetrics
  89:   {
  90: 
  91:     private Font font;
  92:     private GlyphVector glyphVector;
  93: //    private CharacterIterator characterIterator;
  94: //    private int begin;
  95: //    private int limit;
  96:     private FontRenderContext fontRenderContext;
  97:     XLineMetrics(Font f, CharacterIterator ci, int b, int l,
  98:                  FontRenderContext rc)
  99:     {
 100:       font = f;
 101: //      characterIterator = ci;
 102: //      begin = b;
 103: //      limit = l;
 104:       fontRenderContext = rc;
 105:       glyphVector = fontDelegate.createGlyphVector(font, fontRenderContext,
 106:                                                    ci);
 107:     }
 108: 
 109:     public float getAscent()
 110:     {
 111:       return fontDelegate.getAscent(font.getSize(), fontRenderContext.getTransform(),
 112:                              fontRenderContext.isAntiAliased(),
 113:                              fontRenderContext.usesFractionalMetrics(), true);
 114:     }
 115: 
 116:     public int getBaselineIndex()
 117:     {
 118:       // FIXME: Implement this.
 119:       throw new UnsupportedOperationException("Not yet implemented");
 120:     }
 121: 
 122:     public float[] getBaselineOffsets()
 123:     {
 124:       // FIXME: Implement this.
 125:       throw new UnsupportedOperationException("Not yet implemented");
 126:     }
 127: 
 128:     public float getDescent()
 129:     {
 130:       return (int) fontDelegate.getDescent(font.getSize(), IDENDITY, false,
 131:                                            false, false);
 132:     }
 133: 
 134:     public float getHeight()
 135:     {
 136:       return (float) glyphVector.getLogicalBounds().getHeight();
 137:     }
 138: 
 139:     public float getLeading()
 140:     {
 141:       return getHeight() - getAscent() - getDescent();
 142:     }
 143: 
 144:     public int getNumChars()
 145:     {
 146:       // FIXME: Implement this.
 147:       throw new UnsupportedOperationException("Not yet implemented");
 148:     }
 149: 
 150:     public float getStrikethroughOffset()
 151:     {
 152:       return 0.F;
 153:     }
 154: 
 155:     public float getStrikethroughThickness()
 156:     {
 157:       return 0.F;
 158:     }
 159: 
 160:     public float getUnderlineOffset()
 161:     {
 162:       return 0.F;
 163:     }
 164: 
 165:     public float getUnderlineThickness()
 166:     {
 167:       return 0.F;
 168:     }
 169:     
 170:   }
 171: 
 172:   private class XFontMetrics
 173:     extends FontMetrics
 174:   {
 175:     /**
 176:      * A cached point instance, to be used in #charWidth().
 177:      */
 178:     private Point2D cachedPoint = new Point2D.Double();
 179: 
 180:     XFontMetrics(Font f)
 181:     {
 182:       super(f);
 183:     }
 184: 
 185:     public int getAscent()
 186:     {
 187:       return (int) fontDelegate.getAscent(getFont().getSize(), IDENDITY,
 188:                                           false, false, false);
 189:     }
 190: 
 191:     public int getDescent()
 192:     {
 193:       return (int) fontDelegate.getDescent(getFont().getSize(), IDENDITY,
 194:                                            false, false, false);
 195:     }
 196:     
 197:     public int getHeight()
 198:     {
 199:       GlyphVector gv = fontDelegate.createGlyphVector(getFont(),
 200:                     new FontRenderContext(IDENDITY, false, false),
 201:                     new StringCharacterIterator("m"));
 202:       Rectangle2D b = gv.getVisualBounds();
 203:       return (int) b.getHeight();
 204:     }
 205: 
 206:     public int charWidth(char c)
 207:     {
 208:       int code = fontDelegate.getGlyphIndex(c);
 209:       Point2D advance = cachedPoint;
 210:       fontDelegate.getAdvance(code, font.getSize2D(), IDENDITY,
 211:                               false, false, true, advance);
 212:       return (int) advance.getX();
 213:     }
 214: 
 215:     public int charsWidth(char[] chars, int offs, int len)
 216:     {
 217:       return stringWidth(new String(chars, offs, len));
 218:     }
 219: 
 220:     public int stringWidth(String s)
 221:     {
 222:       GlyphVector gv = fontDelegate.createGlyphVector(getFont(),
 223:                     new FontRenderContext(IDENDITY, false, false),
 224:                     new StringCharacterIterator(s));
 225:       Rectangle2D b = gv.getVisualBounds();
 226:       return (int) b.getWidth();
 227:     }
 228:   }
 229: 
 230:   /**
 231:    * The indendity transform, to be used in several methods.
 232:    */
 233:   private static final AffineTransform IDENDITY = new AffineTransform();
 234: 
 235:   private FontDelegate fontDelegate;
 236: 
 237:   XFontPeer2(String name, int style, int size)
 238:   {
 239:     super(name, style, size);
 240:     try
 241:       {
 242:         File fontfile = new File("/usr/share/fonts/truetype/freefont/FreeSans.ttf");
 243:         FileInputStream in = new FileInputStream(fontfile);
 244:         FileChannel ch = in.getChannel();
 245:         ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
 246:                                    fontfile.length());
 247:         fontDelegate = FontFactory.createFonts(buffer)[0];
 248:       }
 249:     catch (Exception ex)
 250:       {
 251:         ex.printStackTrace();
 252:       }
 253:   }
 254: 
 255:   XFontPeer2(String name, Map atts)
 256:   {
 257:     super(name, atts);
 258:     try
 259:       {
 260:         File fontfile = new File("/usr/share/fonts/truetype/freefont/FreeSans.ttf");
 261:         FileInputStream in = new FileInputStream(fontfile);
 262:         FileChannel ch = in.getChannel();
 263:         ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
 264:                                    fontfile.length());
 265:         fontDelegate = FontFactory.createFonts(buffer)[0];
 266:       }
 267:     catch (Exception ex)
 268:       {
 269:         ex.printStackTrace();
 270:       }
 271:   }
 272: 
 273:   public boolean canDisplay(Font font, int c)
 274:   {
 275:     // FIXME: Implement this.
 276:     throw new UnsupportedOperationException("Not yet implemented");
 277:   }
 278: 
 279:   public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit)
 280:   {
 281:     // FIXME: Implement this.
 282:     throw new UnsupportedOperationException("Not yet implemented");
 283:   }
 284: 
 285:   public String getSubFamilyName(Font font, Locale locale)
 286:   {
 287:     // FIXME: Implement this.
 288:     throw new UnsupportedOperationException("Not yet implemented");
 289:   }
 290: 
 291:   public String getPostScriptName(Font font)
 292:   {
 293:     // FIXME: Implement this.
 294:     throw new UnsupportedOperationException("Not yet implemented");
 295:   }
 296: 
 297:   public int getNumGlyphs(Font font)
 298:   {
 299:     // FIXME: Implement this.
 300:     throw new UnsupportedOperationException("Not yet implemented");
 301:   }
 302: 
 303:   public int getMissingGlyphCode(Font font)
 304:   {
 305:     // FIXME: Implement this.
 306:     throw new UnsupportedOperationException("Not yet implemented");
 307:   }
 308: 
 309:   public byte getBaselineFor(Font font, char c)
 310:   {
 311:     // FIXME: Implement this.
 312:     throw new UnsupportedOperationException("Not yet implemented");
 313:   }
 314: 
 315:   public String getGlyphName(Font font, int glyphIndex)
 316:   {
 317:     // FIXME: Implement this.
 318:     throw new UnsupportedOperationException("Not yet implemented");
 319:   }
 320: 
 321:   public GlyphVector createGlyphVector(Font font, FontRenderContext frc, CharacterIterator ci)
 322:   {
 323:     return fontDelegate.createGlyphVector(font, frc, ci);
 324:   }
 325: 
 326:   public GlyphVector createGlyphVector(Font font, FontRenderContext ctx, int[] glyphCodes)
 327:   {
 328:     // FIXME: Implement this.
 329:     throw new UnsupportedOperationException("Not yet implemented");
 330:   }
 331: 
 332:   public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc, char[] chars, int start, int limit, int flags)
 333:   {
 334:     StringCharacterIterator i = new StringCharacterIterator(new String(chars), start, limit, 0);
 335:     return fontDelegate.createGlyphVector(font, frc, i);
 336:   }
 337: 
 338:   public FontMetrics getFontMetrics(Font font)
 339:   {
 340:     return new XFontMetrics(font);
 341:   }
 342: 
 343:   public boolean hasUniformLineMetrics(Font font)
 344:   {
 345:     // FIXME: Implement this.
 346:     throw new UnsupportedOperationException("Not yet implemented");
 347:   }
 348: 
 349:   public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext rc)
 350:   {
 351:     return new XLineMetrics(font, ci, begin, limit, rc);
 352:   }
 353: 
 354:   public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc)
 355:   {
 356:     // FIXME: Implement this.
 357:     throw new UnsupportedOperationException("Not yet implemented");
 358:   }
 359: 
 360:   /**
 361:    * Encodes a font name + style + size specification into a X logical font
 362:    * description (XLFD) as described here:
 363:    *
 364:    * http://www.meretrx.com/e93/docs/xlfd.html
 365:    *
 366:    * This is implemented to look up the font description in the
 367:    * fonts.properties of this package.
 368:    *
 369:    * @param name the font name
 370:    * @param atts the text attributes
 371:    *
 372:    * @return the encoded font description
 373:    */
 374:   static String encodeFont(String name, Map atts)
 375:   {
 376:     String family = name;
 377:     if (family == null || family.equals(""))
 378:       family = (String) atts.get(TextAttribute.FAMILY);
 379:     if (family == null)
 380:       family = "SansSerif";
 381: 
 382:     int size = 12;
 383:     Float sizeFl = (Float) atts.get(TextAttribute.SIZE);
 384:     if (sizeFl != null)
 385:       size = sizeFl.intValue();
 386: 
 387:     int style = 0;
 388:     // Detect italic attribute.
 389:     Float posture = (Float) atts.get(TextAttribute.POSTURE);
 390:     if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR))
 391:       style |= Font.ITALIC;
 392: 
 393:     // Detect bold attribute.
 394:     Float weight = (Float) atts.get(TextAttribute.WEIGHT);
 395:     if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0)
 396:       style |= Font.BOLD;
 397: 
 398:     return encodeFont(name, style, size);
 399:   }
 400: 
 401:   /**
 402:    * Encodes a font name + style + size specification into a X logical font
 403:    * description (XLFD) as described here:
 404:    *
 405:    * http://www.meretrx.com/e93/docs/xlfd.html
 406:    *
 407:    * This is implemented to look up the font description in the
 408:    * fonts.properties of this package.
 409:    *
 410:    * @param name the font name
 411:    * @param style the font style
 412:    * @param size the font size
 413:    *
 414:    * @return the encoded font description
 415:    */
 416:   static String encodeFont(String name, int style, int size)
 417:   {
 418:     StringBuilder key = new StringBuilder();
 419:     key.append(validName(name));
 420:     key.append('.');
 421:     switch (style)
 422:     {
 423:       case Font.BOLD:
 424:         key.append("bold");
 425:         break;
 426:       case Font.ITALIC:
 427:         key.append("italic");
 428:         break;
 429:       case (Font.BOLD | Font.ITALIC):
 430:         key.append("bolditalic");
 431:         break;
 432:       case Font.PLAIN:
 433:       default:
 434:         key.append("plain");
 435:       
 436:     }
 437: 
 438:     String protoType = fontProperties.getProperty(key.toString());
 439:     int s = size;
 440:     return protoType.replaceFirst("%d", String.valueOf(s * 10));
 441:   }
 442: 
 443:   /**
 444:    * Checks the specified font name for a valid font name. If the font name
 445:    * is not known, then this returns 'sansserif' as fallback.
 446:    *
 447:    * @param name the font name to check
 448:    *
 449:    * @return a valid font name
 450:    */
 451:   static String validName(String name)
 452:   {
 453:     String retVal;
 454:     if (name.equalsIgnoreCase("sansserif")
 455:         || name.equalsIgnoreCase("serif")
 456:         || name.equalsIgnoreCase("monospaced")
 457:         || name.equalsIgnoreCase("dialog")
 458:         || name.equalsIgnoreCase("dialoginput"))
 459:       {
 460:         retVal = name.toLowerCase();
 461:       }
 462:     else
 463:       {
 464:         retVal = "sansserif";
 465:       }
 466:     return retVal;
 467:   }
 468: }