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