Source for gnu.java.awt.font.opentype.OpenTypeFont

   1: /* OpenTypeFont.java -- Manages OpenType and TrueType fonts.
   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.font.opentype;
  39: 
  40: import java.awt.Font;
  41: import java.awt.FontFormatException;
  42: import java.awt.font.FontRenderContext;
  43: import java.awt.font.GlyphVector;
  44: import java.awt.font.OpenType;
  45: import java.awt.geom.AffineTransform;
  46: import java.awt.geom.GeneralPath;
  47: import java.awt.geom.Point2D;
  48: import java.nio.ByteBuffer;
  49: import java.text.CharacterIterator;
  50: import java.util.Locale;
  51: 
  52: import gnu.java.awt.font.FontDelegate;
  53: import gnu.java.awt.font.GNUGlyphVector;
  54: import gnu.java.awt.font.opentype.truetype.TrueTypeScaler;
  55: 
  56: 
  57: /**
  58:  * A font that takes its data from OpenType or TrueType font tables.
  59:  *
  60:  * <p>OpenType is an extension of the TrueType font format. In addition
  61:  * to tables for names, kerning or layout, it also stores the shapes
  62:  * of individual glyphs. Three formats are recognized for glyphs:
  63:  * Quadratic splines (classic TrueType), cubic splines (PostScript),
  64:  * and bitmaps.
  65:  *
  66:  * @see <a
  67:  * href="http://partners.adobe.com/asn/tech/type/opentype/">Adobe&#x2019;s
  68:  * OpenType specification</a>
  69:  *
  70:  * @see <a
  71:  * href="http://developer.apple.com/fonts/TTRefMan/">Apple&#x2019;s</code>
  72:  * TrueType specification</a>
  73:  *
  74:  * @author Sascha Brawer (brawer@dandelis.ch)
  75:  */
  76: public final class OpenTypeFont
  77:   implements FontDelegate
  78: {
  79:   static final int TAG_OTTO = 0x4f54544f; // 'OTTO'
  80:   static final int TAG_SFNT = 0x73666e74; // 'sfnt'
  81:   static final int TAG_TRUE = 0x74727565; // 'true'
  82:   static final int TAG_TTCF = 0x74746366; // 'ttcf'
  83:   static final int TAG_ZAPF = 0x5a617066; // 'Zapf'
  84:   
  85: 
  86:   /**
  87:    * A buffer containing the font data. Note that this may well be an
  88:    * instance of the subclass MappedByteBuffer, in which case the
  89:    * virtual memory subsystem can more efficiently handle requests for
  90:    * font data. This is especially recommended for large font files
  91:    * that contain many glyphs that are rarely accessed.
  92:    */
  93:   ByteBuffer buf;
  94: 
  95: 
  96:   /**
  97:    * The number of glyphs in this font.
  98:    */
  99:   final int numGlyphs;
 100: 
 101:   int[] tableTag, tableStart, tableLength;
 102: 
 103: 
 104:   /**
 105:    * The version of the font in 16.16 fixed-point encoding, for
 106:    * example 0x00010000 for version 1.0. There are also two special
 107:    * version IDs used by fonts for Apple Macintosh, namely 'true'
 108:    * (0x74727565) and 'typ1'. OpenType fonts sometimes have 'OTTO' as
 109:    * their version.
 110:    */
 111:   private int version;
 112: 
 113:   
 114:   /**
 115:    * The number of font units per em. For fonts with TrueType
 116:    * outlines, this is usually a power of two (such as 2048). For
 117:    * OpenType fonts with PostScript outlines, other values are
 118:    * acceptable (such as 1000).
 119:    */
 120:   private int unitsPerEm;
 121: 
 122: 
 123:   /**
 124:    * A factor to convert font units into ems. This value is <code>1 /
 125:    * unitsPerEm</code>.
 126:    */
 127:   private float emsPerUnit;
 128: 
 129: 
 130:   /**
 131:    * The scaler to which the actual scaling work is delegated.
 132:    */
 133:   private Scaler scaler;
 134:   
 135: 
 136:   /**
 137:    * A delegate object for mapping Unicode UCS-4 codepoints to glyph
 138:    * IDs.
 139:    */
 140:   private CharGlyphMap cmap;
 141: 
 142: 
 143:   /**
 144:    * A delegate object for providing a name for each glyph.
 145:    */
 146:   private GlyphNamer glyphNamer;
 147: 
 148:   
 149:   /**
 150:    * Constructs an OpenType or TrueType font.
 151:    *
 152:    * @param buf a buffer with the contents of the font file. It is
 153:    * recommended to use a <code>MappedByteBuffer</code> for very
 154:    * large font files.
 155:    *
 156:    * @param offsetTablePosition the position of the OpenType offset
 157:    * table in the font file. The offset table of most OpenType and
 158:    * TrueType fonts starts at position 0.  However, so-called TrueType
 159:    * Collections support multiple OpenType fonts in a single file,
 160:    * which allows sharing some glyphs between fonts. If many glyphs
 161:    * are shared (for example all the Kanji glyphs between multiple
 162:    * Japanese fonts), the space savings can be considerable. In that
 163:    * case, the offset table of each individual font would start at its
 164:    * own position.
 165:    *
 166:    * @throws java.awt.FontFormatException if the font data is
 167:    * not in OpenType or TrueType format.
 168:    */
 169:   OpenTypeFont(ByteBuffer buf, int offsetTablePosition)
 170:     throws FontFormatException
 171:   {
 172:     int numTables, searchRange, entrySelector, rangeShift;
 173: 
 174:     //buf = buf.duplicate();
 175:     this.buf = buf;
 176:     buf.limit(buf.capacity());
 177:     buf.position(offsetTablePosition);
 178: 
 179:     /* Check that the font data is in a supported format. */
 180:     version = buf.getInt();
 181:     switch (version)
 182:     {
 183:     case 0x00010000:        // Microsoft TrueType
 184:     case OpenType.TAG_TYP1: // Adobe PostScript embeded in Apple SFNT ('typ1')
 185:     case TAG_SFNT:          // Apple TrueType
 186:     case TAG_TRUE:          // Apple TrueType
 187:     case TAG_OTTO:          // OpenType
 188:       break;
 189: 
 190:     default:
 191:       throw new FontFormatException("not in OpenType or TrueType format");
 192:     }
 193: 
 194:     numTables = buf.getShort();
 195:     searchRange = buf.getShort();
 196:     entrySelector = buf.getShort();
 197:     rangeShift = buf.getShort();
 198: 
 199:     tableTag = new int[numTables];
 200:     tableStart = new int[numTables];
 201:     tableLength = new int[numTables];
 202:     int lastTag = 0;
 203:     for (int i = 0; i < numTables; i++)
 204:     {
 205:       tableTag[i] = buf.getInt();
 206:       if (lastTag >= tableTag[i])
 207:         throw new FontFormatException("unordered OpenType table");
 208: 
 209:       buf.getInt(); // ignore checksum
 210:       tableStart[i] = buf.getInt();
 211:       tableLength[i] = buf.getInt();
 212: 
 213:       //System.out.println(tagToString(tableTag[i]) + ", " + tableLength[i]);
 214:     }
 215: 
 216:     ByteBuffer head = getFontTable(OpenType.TAG_HEAD);
 217:     if ((head.getInt(0) != 0x00010000)
 218:         || (head.getInt(12) != 0x5f0f3cf5))
 219:         throw new FontFormatException("unsupported head version");
 220: 
 221:     unitsPerEm = head.getChar(18);
 222:     emsPerUnit = 1.0f / (float) unitsPerEm;
 223: 
 224: 
 225:     ByteBuffer maxp = getFontTable(OpenType.TAG_MAXP);
 226:     int maxpVersion = maxp.getInt(0);
 227:     switch (maxpVersion)
 228:     {
 229:     case 0x00005000: /* version 0.5, with wrong fractional part */
 230:       numGlyphs = maxp.getChar(4);
 231:       break;
 232: 
 233:     case 0x00010000: /* version 1.0 */
 234:       numGlyphs = maxp.getChar(4);
 235:       scaler = new TrueTypeScaler(unitsPerEm,
 236:                                   getFontTable(OpenType.TAG_HHEA),
 237:                                   getFontTable(OpenType.TAG_HMTX),
 238:                                   getFontTable(OpenType.TAG_VHEA),
 239:                                   getFontTable(OpenType.TAG_VMTX),
 240:                                   maxp,
 241:                                   getFontTable(OpenType.TAG_CVT),
 242:                                   getFontTable(OpenType.TAG_FPGM),
 243:                                   /* loca format */ head.getShort(50),
 244:                                   getFontTable(OpenType.TAG_LOCA),
 245:                                   getFontTable(OpenType.TAG_GLYF),
 246:                                   getFontTable(OpenType.TAG_PREP));
 247:       break;
 248: 
 249:     default:
 250:       throw new FontFormatException("unsupported maxp version");
 251:     }
 252:   }
 253: 
 254: 
 255:   /**
 256:    * Determines the index of a table into the offset table.  The
 257:    * result can be used to find the offset and length of a table, as
 258:    * in <code>tableStart[getTableIndex(TAG_NAME)]</code>.
 259:    *
 260:    * @param tag the table identifier, for instance
 261:    * <code>OpenType.TAG_NAME</code>.
 262:    *
 263:    * @return the index of that table into the offset table, or
 264:    * -1 if the font does not contain the table specified by
 265:    * <code>tag</code>.
 266:    */
 267:   private int getTableIndex(int tag)
 268:   {
 269:     /* FIXME: Since the font specification requires tableTag[] to be
 270:      * ordered, one should do binary search here.
 271:      */
 272:     for (int i = 0; i < tableTag.length; i++)
 273:       if (tableTag[i] == tag)
 274:         return i;
 275:     return -1;
 276:   }
 277:   
 278:   
 279: 
 280:   /**
 281:    * Returns the name of the family to which this font face belongs,
 282:    * for example <i>&#x201c;Univers&#x201d;</i>.
 283:    *
 284:    * @param locale the locale for which to localize the name.
 285:    *
 286:    * @return the family name.
 287:    */
 288:   public synchronized String getFamilyName(Locale locale)
 289:   {
 290:     String name;
 291: 
 292:     if (locale == null)
 293:       locale = Locale.getDefault();
 294: 
 295:     name = getName(NameDecoder.NAME_FAMILY, locale);
 296:     if (name == null)
 297:       name = getName(NameDecoder.NAME_FAMILY, Locale.ENGLISH);
 298:     if (name == null)
 299:       name = getName(NameDecoder.NAME_FAMILY, /* any language */ null);
 300:     if (name == null)
 301:       name = getName(NameDecoder.NAME_FULL, locale);
 302:     if (name == null)
 303:       name = getName(NameDecoder.NAME_FULL, /* any language */ null);
 304:     return name;
 305:   }
 306: 
 307: 
 308:   /**
 309:    * Returns the name of this font face inside the family, for example
 310:    * <i>&#x201c;Light&#x201d;</i>.
 311:    *
 312:    * @param locale the locale for which to localize the name.
 313:    *
 314:    * @return the name of the face inside its family.
 315:    */
 316:   public synchronized String getSubFamilyName(Locale locale)
 317:   {
 318:     String name;
 319: 
 320:     if (locale == null)
 321:       locale = Locale.getDefault();
 322: 
 323:     name = getName(NameDecoder.NAME_SUBFAMILY, locale);
 324:     if (name == null)
 325:     {
 326:       name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH);
 327:       if ("Regular".equals(name))
 328:         name = null;
 329:     }
 330: 
 331:     if (name == null)
 332:     {
 333:       String lang = locale.getLanguage();
 334:       if ("de".equals(lang))
 335:         name = "Standard";
 336:       else if ("fr".equals(lang))
 337:         name = "Standard";
 338:       else if ("it".equals(lang))
 339:         name = "Normale";
 340:       else if ("nl".equals(lang))
 341:         name = "Normaal";
 342:       else if ("fi".equals(lang))
 343:         name = "Normaali";
 344:       else if ("sv".equals(lang))
 345:         name = "Normal";
 346:       else
 347:         name = "Regular";
 348:     }
 349: 
 350:     return name;
 351:   }
 352:   
 353:   
 354: 
 355:   /**
 356:    * Returns the full name of this font face, for example
 357:    * <i>&#x201c;Univers Light&#x201d;</i>.
 358:    *
 359:    * @param locale the locale for which to localize the name.
 360:    *
 361:    * @return the face name.
 362:    */
 363:   public synchronized String getFullName(Locale locale)
 364:   {
 365:     String name;
 366: 
 367:     if (locale == null)
 368:       locale = Locale.getDefault();
 369: 
 370:     name = getName(NameDecoder.NAME_FULL, locale);
 371:     if (name == null)
 372:       name = getName(NameDecoder.NAME_FULL, Locale.ENGLISH);
 373:     if (name == null)
 374:       name = getName(NameDecoder.NAME_FULL, /* any language */ null);
 375: 
 376:     return name;
 377:   }
 378: 
 379: 
 380:   /**
 381:    * Returns the PostScript name of this font face, for example
 382:    * <i>&#x201c;Univers-Light&#x201d;</i>.
 383:    *
 384:    * @return the PostScript name, or <code>null</code> if the font
 385:    * does not provide a PostScript name.
 386:    */
 387:   public synchronized String getPostScriptName()
 388:   {
 389:     return getName(NameDecoder.NAME_POSTSCRIPT, /* any language */ null);
 390:   }
 391: 
 392: 
 393:   /**
 394:    * Returns the number of glyphs in this font face.
 395:    */
 396:   public int getNumGlyphs()
 397:   {
 398:     /* No synchronization is needed because the number of glyphs is
 399:      * set in the constructor, and it cannot change during the
 400:      * lifetime of the object.
 401:      */
 402:     return numGlyphs;
 403:   }
 404:   
 405: 
 406:   /**
 407:    * Returns the index of the glyph which gets displayed if the font
 408:    * cannot map a Unicode code point to a glyph. Many fonts show this
 409:    * glyph as an empty box.
 410:    */
 411:   public int getMissingGlyphCode()
 412:   {
 413:     /* No synchronization is needed because the result is constant. */
 414:     return 0;
 415:   }
 416: 
 417: 
 418:   /**
 419:    * The font&#x2019;s name table, or <code>null</code> if this
 420:    * table has not yet been accessed.
 421:    */
 422:   private ByteBuffer nameTable;
 423: 
 424: 
 425:   /**
 426:    * Extracts a String from the font&#x2019;s name table.
 427:    *
 428:    * @param name the numeric TrueType or OpenType name ID.
 429:    *
 430:    * @param locale the locale for which names shall be localized, or
 431:    * <code>null</code> if the locale does mot matter because the name
 432:    * is known to be language-independent (for example, because it is
 433:    * the PostScript name).
 434:    */
 435:   private String getName(int name, Locale locale)
 436:   {
 437:     if (nameTable == null)
 438:       nameTable = getFontTable(OpenType.TAG_NAME);
 439:     return NameDecoder.getName(nameTable, name, locale);
 440:   }
 441: 
 442: 
 443:   /**
 444:    * Returns the version of the font.
 445:    *
 446:    * @see java.awt.font.OpenType#getVersion
 447:    *
 448:    * @return the version in 16.16 fixed-point encoding, for example
 449:    * 0x00010000 for version 1.0.
 450:    */
 451:   public int getVersion()
 452:   {
 453:     /* No synchronization is needed because the version is set in the
 454:      * constructor, and it cannot change during the lifetime of the
 455:      * object.
 456:      */
 457:     return version;
 458:   }
 459: 
 460: 
 461:   /**
 462:    * Creates a view buffer for an OpenType table. The caller can
 463:    * access the returned buffer without needing to synchronize access
 464:    * from multiple threads.
 465:    *
 466:    * @param tag the table identifier, for example
 467:    * <code>OpenType.GLYF</code>.
 468:    *
 469:    * @return a slice of the underlying buffer containing the table, or
 470:    * <code>null</code> if the font does not contain the requested
 471:    * table.
 472:    */
 473:   public synchronized ByteBuffer getFontTable(int tag)
 474:   {
 475:     int index, start, len;
 476:     ByteBuffer result;
 477: 
 478:     index = getTableIndex(tag);
 479:     if (index < 0)
 480:       return null;
 481: 
 482:     start = tableStart[index];
 483:     len = tableLength[index];
 484:     buf.limit(start + len).position(start);
 485:     result = buf.slice();
 486:     result.limit(len);
 487:     return result;
 488:   }
 489:   
 490: 
 491:   /**
 492:    * Returns the size of one of the tables in the font,
 493:    * or -1 if the table does not exist.
 494:    */
 495:   public int getFontTableSize(int tag)
 496:   {
 497:     int index = getTableIndex(tag);
 498:     if (index == -1)
 499:       return index;
 500:     return tableLength[index];
 501:   }
 502: 
 503: 
 504:   private CharGlyphMap getCharGlyphMap()
 505:   {
 506:     if (cmap != null)
 507:       return cmap;
 508:  
 509:     synchronized (this)
 510:     {
 511:       if (cmap == null)
 512:       {
 513:         int index = getTableIndex(OpenType.TAG_CMAP);
 514:         int start = tableStart[index];
 515:         buf.limit(start + tableLength[index]).position(start);
 516:         cmap = CharGlyphMap.forTable(buf);
 517:       }
 518:       return cmap;
 519:     }
 520:   }
 521: 
 522: 
 523: 
 524:   /**
 525:    * Looks up a glyph in the font&#x2019;s <code>cmap</code> tables,
 526:    * without performing any glyph substitution or reordering. Because
 527:    * of this limitation, this method cannot be used for script systems
 528:    * that need advanced glyph mapping, such as Arabic, Korean, or even
 529:    * Latin with exotic accents.
 530:    *
 531:    * <p>It is safe to call this method from any thread.
 532:    *
 533:    * @param ucs4 the Unicode codepoint in the 32-bit Unicode character
 534:    * set UCS-4. Because UTF-16 surrogates do not correspond to a single
 535:    * glyph, it does not make sense to pass them here.
 536:    *
 537:    * @return the glyph index, or zero if the font does not contain
 538:    * a glyph for the specified codepoint.
 539:    */
 540:   public int getGlyph(int ucs4)
 541:   {
 542:     return getCharGlyphMap().getGlyph(ucs4);
 543:   }
 544: 
 545:   
 546:   /**
 547:    * Creates a GlyphVector by mapping each character in a
 548:    * CharacterIterator to the corresponding glyph.
 549:    *
 550:    * <p>The mapping takes only the font&#x2019;s <code>cmap</code>
 551:    * tables into consideration. No other operations (such as glyph
 552:    * re-ordering, composition, or ligature substitution) are
 553:    * performed. This means that the resulting GlyphVector will not be
 554:    * correct for text in languages that have complex
 555:    * character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or
 556:    * Thai.
 557:    *
 558:    * @param font the font object that the created GlyphVector
 559:    * will return when it gets asked for its font. This argument is
 560:    * needed because the public API works with java.awt.Font,
 561:    * not with some private delegate like OpenTypeFont.
 562:    *
 563:    * @param frc the font rendering parameters that are used for
 564:    * measuring glyphs. The exact placement of text slightly depends on
 565:    * device-specific characteristics, for instance the device
 566:    * resolution or anti-aliasing. For this reason, any measurements
 567:    * will only be accurate if the passed
 568:    * <code>FontRenderContext</code> correctly reflects the relevant
 569:    * parameters. Hence, <code>frc</code> should be obtained from the
 570:    * same <code>Graphics2D</code> that will be used for drawing, and
 571:    * any rendering hints should be set to the desired values before
 572:    * obtaining <code>frc</code>.
 573:    *
 574:    * @param ci a CharacterIterator for iterating over the
 575:    * characters to be displayed.
 576:    */
 577:   public synchronized GlyphVector createGlyphVector(Font font,
 578:                                                     FontRenderContext frc,
 579:                                                     CharacterIterator ci)
 580:   {
 581:     CharGlyphMap cmap;    
 582:     int numGlyphs;
 583:     int[] glyphs;
 584:     int glyph;
 585:     int c;
 586: 
 587:     cmap = getCharGlyphMap();
 588:     numGlyphs = ci.getEndIndex() - ci.getBeginIndex();
 589:     glyphs = new int[numGlyphs];
 590:     glyph = 0;
 591:     for (c = ci.first(); c != CharacterIterator.DONE; c = ci.next())
 592:     {
 593:       /* handle surrogate pairs */
 594:       if (c >> 10 == 0x36) // U+D800 .. U+DBFF: High surrogate
 595:         c = (((c & 0x3ff) << 10) | (ci.next() & 0x3ff)) + 0x10000;
 596:       glyphs[glyph] = cmap.getGlyph(c);
 597:       glyph += 1;
 598:     }
 599: 
 600:     /* If we had surrogates, the allocated array is too large.
 601:      * Because this will occur very rarely, it seems acceptable to
 602:      * re-allocate a shorter array and copy the contents around.
 603:      */
 604:     if (glyph != numGlyphs)
 605:     {
 606:       int[] newGlyphs = new int[glyph];
 607:       System.arraycopy(glyphs, 0, newGlyphs, 0, glyph);
 608:       glyphs = newGlyphs;
 609:     }
 610: 
 611:     return new GNUGlyphVector(this, font, frc, glyphs);
 612:   }
 613: 
 614: 
 615: 
 616:   /**
 617:    * Determines the advance width for a glyph.
 618:    *
 619:    * @param glyphIndex the glyph whose advance width is to be
 620:    * determined.
 621:    *
 622:    * @param pointSize the point size of the font.
 623:    *
 624:    * @param transform a transform that is applied in addition to
 625:    * scaling to the specified point size. This is often used for
 626:    * scaling according to the device resolution. Those who lack any
 627:    * aesthetic sense may also use the transform to slant or stretch
 628:    * glyphs.
 629:    *
 630:    * @param antialias <code>true</code> for anti-aliased rendering,
 631:    * <code>false</code> for normal rendering. For hinted fonts,
 632:    * this parameter may indeed affect the result.
 633:    *
 634:    * @param fractionalMetrics <code>true</code> for fractional metrics,
 635:    * <code>false</code> for rounding the result to a pixel boundary.
 636:    *
 637:    * @param horizontal <code>true</code> for horizontal line layout,
 638:    * <code>false</code> for vertical line layout.
 639:    *
 640:    * @param advance a point whose <code>x</code> and <code>y</code>
 641:    * fields will hold the advance in each direction. It is possible
 642:    * that both values are non-zero, for example if
 643:    * <code>transform</code> is a rotation, or in the case of Urdu
 644:    * fonts.
 645:    */
 646:   public synchronized void getAdvance(int glyphIndex,
 647:                                       float pointSize,
 648:                                       AffineTransform transform,
 649:                                       boolean antialias,
 650:                                       boolean fractionalMetrics,
 651:                                       boolean horizontal,
 652:                                       Point2D advance)
 653:   {
 654:     /* Delegate the measurement to the scaler.  The synchronization is
 655:      * needed because the scaler is not synchronized.
 656:      */
 657:     scaler.getAdvance(glyphIndex, pointSize, transform,
 658:                       antialias, fractionalMetrics, horizontal,
 659:                       advance);
 660:   }
 661: 
 662: 
 663:   /**
 664:    * Returns the shape of a glyph.
 665:    *
 666:    * @param glyph the glyph whose advance width is to be determined
 667:    *
 668:    * @param pointSize the point size of the font.
 669:    *
 670:    * @param transform a transform that is applied in addition to
 671:    * scaling to the specified point size. This is often used for
 672:    * scaling according to the device resolution. Those who lack any
 673:    * aesthetic sense may also use the transform to slant or stretch
 674:    * glyphs.
 675:    *
 676:    * @param antialias <code>true</code> for anti-aliased rendering,
 677:    * <code>false</code> for normal rendering. For hinted fonts, this
 678:    * parameter may indeed affect the result.
 679:    *
 680:    * @param fractionalMetrics <code>true</code> for fractional
 681:    * metrics, <code>false</code> for rounding the result to a pixel
 682:    * boundary.
 683:    *
 684:    * @return the scaled and grid-fitted outline of the specified
 685:    * glyph, or <code>null</code> for bitmap fonts.
 686:    */
 687:   public synchronized GeneralPath getGlyphOutline(int glyph,
 688:                                                   float pointSize,
 689:                                                   AffineTransform transform,
 690:                                                   boolean antialias,
 691:                                                   boolean fractionalMetrics)
 692:   {
 693:     /* The synchronization is needed because the scaler is not
 694:      * synchronized.
 695:      */
 696:     return scaler.getOutline(glyph, pointSize, transform,
 697:                              antialias, fractionalMetrics);
 698:   }
 699: 
 700: 
 701:   /**
 702:    * Returns a name for the specified glyph. This is useful for
 703:    * generating PostScript or PDF files that embed some glyphs of a
 704:    * font.
 705:    *
 706:    * <p><b>Names are not unique:</b> Under some rare circumstances,
 707:    * the same name can be returned for different glyphs. It is
 708:    * therefore recommended that printer drivers check whether the same
 709:    * name has already been returned for antoher glyph, and make the
 710:    * name unique by adding the string ".alt" followed by the glyph
 711:    * index.</p>
 712:    *
 713:    * <p>This situation would occur for an OpenType or TrueType font
 714:    * that has a <code>post</code> table of format 3 and provides a
 715:    * mapping from glyph IDs to Unicode sequences through a
 716:    * <code>Zapf</code> table. If the same sequence of Unicode
 717:    * codepoints leads to different glyphs (depending on contextual
 718:    * position, for example, or on typographic sophistication level),
 719:    * the same name would get synthesized for those glyphs.
 720:    *
 721:    * @param glyphIndex the glyph whose name the caller wants to
 722:    * retrieve.
 723:    */
 724:   public synchronized String getGlyphName(int glyphIndex)
 725:   {
 726:     if (glyphNamer == null)
 727:       glyphNamer = GlyphNamer.forTables(numGlyphs,
 728:                                         getFontTable(OpenType.TAG_POST),
 729:                                         getFontTable(TAG_ZAPF));
 730: 
 731:     return glyphNamer.getGlyphName(glyphIndex);
 732:   }
 733: 
 734: 
 735:   /**
 736:    * Determines the distance between the base line and the highest
 737:    * ascender.
 738:    *
 739:    * @param pointSize the point size of the font.
 740:    *
 741:    * @param transform a transform that is applied in addition to
 742:    * scaling to the specified point size. This is often used for
 743:    * scaling according to the device resolution. Those who lack any
 744:    * aesthetic sense may also use the transform to slant or stretch
 745:    * glyphs.
 746:    *
 747:    * @param antialiased <code>true</code> for anti-aliased rendering,
 748:    * <code>false</code> for normal rendering. For hinted fonts,
 749:    * this parameter may indeed affect the result.
 750:    *
 751:    * @param fractionalMetrics <code>true</code> for fractional metrics,
 752:    * <code>false</code> for rounding the result to a pixel boundary.
 753:    *
 754:    * @param horizontal <code>true</code> for horizontal line layout,
 755:    * <code>false</code> for vertical line layout.
 756:    *
 757:    * @return the ascent, which usually is a positive number.
 758:    */
 759:   public synchronized float getAscent(float pointSize,
 760:                                       AffineTransform transform,
 761:                                       boolean antialiased,
 762:                                       boolean fractionalMetrics,
 763:                                       boolean horizontal)
 764:   {
 765:     return scaler.getAscent(pointSize, transform,
 766:                             antialiased, fractionalMetrics,
 767:                             horizontal);
 768:   }
 769: 
 770: 
 771:   /**
 772:    * Determines the distance between the base line and the lowest
 773:    * descender.
 774:    *
 775:    * @param pointSize the point size of the font.
 776:    *
 777:    * @param transform a transform that is applied in addition to
 778:    * scaling to the specified point size. This is often used for
 779:    * scaling according to the device resolution. Those who lack any
 780:    * aesthetic sense may also use the transform to slant or stretch
 781:    * glyphs.
 782:    *
 783:    * @param antialiased <code>true</code> for anti-aliased rendering,
 784:    * <code>false</code> for normal rendering. For hinted fonts,
 785:    * this parameter may indeed affect the result.
 786:    *
 787:    * @param fractionalMetrics <code>true</code> for fractional metrics,
 788:    * <code>false</code> for rounding the result to a pixel boundary.
 789:    *
 790:    * @param horizontal <code>true</code> for horizontal line layout,
 791:    * <code>false</code> for vertical line layout.
 792:    *
 793:    * @return the descent, which usually is a nagative number.
 794:    */
 795:   public synchronized float getDescent(float pointSize,
 796:                                        AffineTransform transform,
 797:                                        boolean antialiased,
 798:                                        boolean fractionalMetrics,
 799:                                        boolean horizontal)
 800:   {
 801:     return scaler.getDescent(pointSize, transform,
 802:                              antialiased, fractionalMetrics,
 803:                              horizontal);
 804:   }
 805: 
 806: 
 807:   /**
 808:    * Converts a four-byte tag identifier into a String that can be
 809:    * displayed when debugging this class.
 810:    *
 811:    * @param tag the tag as an <code>int</code>.
 812:    *
 813:    * @return the tag in human-readable form, for example
 814:    * <code>name</code> or <code>glyf</code>.
 815:    */
 816:   static String tagToString(int tag)
 817:   {
 818:     char[] c = new char[4];
 819:     c[0] = (char) ((tag >> 24) & 0xff);
 820:     c[1] = (char) ((tag >> 16) & 0xff);
 821:     c[2] = (char) ((tag >> 8) & 0xff);
 822:     c[3] = (char) (tag & 0xff);
 823:     return new String(c);
 824:   }
 825: }