1 /* 2 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 import java.awt.font.FontRenderContext; 29 import java.awt.font.GlyphVector; 30 import java.awt.font.LineMetrics; 31 import java.awt.font.TextAttribute; 32 import java.awt.font.TextLayout; 33 import java.awt.geom.AffineTransform; 34 import java.awt.geom.Point2D; 35 import java.awt.geom.Rectangle2D; 36 import java.awt.peer.FontPeer; 37 import java.io.*; 38 import java.lang.ref.SoftReference; 39 import java.nio.file.Files; 40 import java.security.AccessController; 41 import java.security.PrivilegedExceptionAction; 42 import java.text.AttributedCharacterIterator.Attribute; 43 import java.text.CharacterIterator; 44 import java.text.StringCharacterIterator; 45 import java.util.Hashtable; 46 import java.util.Locale; 47 import java.util.Map; 48 import sun.font.StandardGlyphVector; 49 50 import sun.font.AttributeMap; 51 import sun.font.AttributeValues; 52 import sun.font.CompositeFont; 53 import sun.font.CreatedFontTracker; 54 import sun.font.Font2D; 55 import sun.font.Font2DHandle; 56 import sun.font.FontAccess; 57 import sun.font.FontManager; 58 import sun.font.FontManagerFactory; 59 import sun.font.FontUtilities; 60 import sun.font.GlyphLayout; 61 import sun.font.FontLineMetrics; 62 import sun.font.CoreMetrics; 63 64 import static sun.font.EAttribute.*; 65 66 /** 67 * The <code>Font</code> class represents fonts, which are used to 68 * render text in a visible way. 69 * A font provides the information needed to map sequences of 70 * <em>characters</em> to sequences of <em>glyphs</em> 71 * and to render sequences of glyphs on <code>Graphics</code> and 72 * <code>Component</code> objects. 73 * 74 * <h3>Characters and Glyphs</h3> 75 * 76 * A <em>character</em> is a symbol that represents an item such as a letter, 77 * a digit, or punctuation in an abstract way. For example, <code>'g'</code>, 78 * LATIN SMALL LETTER G, is a character. 79 * <p> 80 * A <em>glyph</em> is a shape used to render a character or a sequence of 81 * characters. In simple writing systems, such as Latin, typically one glyph 82 * represents one character. In general, however, characters and glyphs do not 83 * have one-to-one correspondence. For example, the character 'á' 84 * LATIN SMALL LETTER A WITH ACUTE, can be represented by 85 * two glyphs: one for 'a' and one for '´'. On the other hand, the 86 * two-character string "fi" can be represented by a single glyph, an 87 * "fi" ligature. In complex writing systems, such as Arabic or the South 88 * and South-East Asian writing systems, the relationship between characters 89 * and glyphs can be more complicated and involve context-dependent selection 90 * of glyphs as well as glyph reordering. 91 * 92 * A font encapsulates the collection of glyphs needed to render a selected set 93 * of characters as well as the tables needed to map sequences of characters to 94 * corresponding sequences of glyphs. 95 * 96 * <h3>Physical and Logical Fonts</h3> 97 * 98 * The Java Platform distinguishes between two kinds of fonts: 99 * <em>physical</em> fonts and <em>logical</em> fonts. 100 * <p> 101 * <em>Physical</em> fonts are the actual font libraries containing glyph data 102 * and tables to map from character sequences to glyph sequences, using a font 103 * technology such as TrueType or PostScript Type 1. 104 * All implementations of the Java Platform must support TrueType fonts; 105 * support for other font technologies is implementation dependent. 106 * Physical fonts may use names such as Helvetica, Palatino, HonMincho, or 107 * any number of other font names. 108 * Typically, each physical font supports only a limited set of writing 109 * systems, for example, only Latin characters or only Japanese and Basic 110 * Latin. 111 * The set of available physical fonts varies between configurations. 112 * Applications that require specific fonts can bundle them and instantiate 113 * them using the {@link #createFont createFont} method. 114 * <p> 115 * <em>Logical</em> fonts are the five font families defined by the Java 116 * platform which must be supported by any Java runtime environment: 117 * Serif, SansSerif, Monospaced, Dialog, and DialogInput. 118 * These logical fonts are not actual font libraries. Instead, the logical 119 * font names are mapped to physical fonts by the Java runtime environment. 120 * The mapping is implementation and usually locale dependent, so the look 121 * and the metrics provided by them vary. 122 * Typically, each logical font name maps to several physical fonts in order to 123 * cover a large range of characters. 124 * <p> 125 * Peered AWT components, such as {@link Label Label} and 126 * {@link TextField TextField}, can only use logical fonts. 127 * <p> 128 * For a discussion of the relative advantages and disadvantages of using 129 * physical or logical fonts, see the 130 * <a href="http://www.oracle.com/technetwork/java/javase/tech/faq-jsp-138165.html">Internationalization FAQ</a> 131 * document. 132 * 133 * <h3>Font Faces and Names</h3> 134 * 135 * A <code>Font</code> 136 * can have many faces, such as heavy, medium, oblique, gothic and 137 * regular. All of these faces have similar typographic design. 138 * <p> 139 * There are three different names that you can get from a 140 * <code>Font</code> object. The <em>logical font name</em> is simply the 141 * name that was used to construct the font. 142 * The <em>font face name</em>, or just <em>font name</em> for 143 * short, is the name of a particular font face, like Helvetica Bold. The 144 * <em>family name</em> is the name of the font family that determines the 145 * typographic design across several faces, like Helvetica. 146 * <p> 147 * The <code>Font</code> class represents an instance of a font face from 148 * a collection of font faces that are present in the system resources 149 * of the host system. As examples, Arial Bold and Courier Bold Italic 150 * are font faces. There can be several <code>Font</code> objects 151 * associated with a font face, each differing in size, style, transform 152 * and font features. 153 * <p> 154 * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method 155 * of the <code>GraphicsEnvironment</code> class returns an 156 * array of all font faces available in the system. These font faces are 157 * returned as <code>Font</code> objects with a size of 1, identity 158 * transform and default font features. These 159 * base fonts can then be used to derive new <code>Font</code> objects 160 * with varying sizes, styles, transforms and font features via the 161 * <code>deriveFont</code> methods in this class. 162 * 163 * <h3>Font and TextAttribute</h3> 164 * 165 * <p><code>Font</code> supports most 166 * <code>TextAttribute</code>s. This makes some operations, such as 167 * rendering underlined text, convenient since it is not 168 * necessary to explicitly construct a <code>TextLayout</code> object. 169 * Attributes can be set on a Font by constructing or deriving it 170 * using a <code>Map</code> of <code>TextAttribute</code> values. 171 * 172 * <p>The values of some <code>TextAttributes</code> are not 173 * serializable, and therefore attempting to serialize an instance of 174 * <code>Font</code> that has such values will not serialize them. 175 * This means a Font deserialized from such a stream will not compare 176 * equal to the original Font that contained the non-serializable 177 * attributes. This should very rarely pose a problem 178 * since these attributes are typically used only in special 179 * circumstances and are unlikely to be serialized. 180 * 181 * <ul> 182 * <li><code>FOREGROUND</code> and <code>BACKGROUND</code> use 183 * <code>Paint</code> values. The subclass <code>Color</code> is 184 * serializable, while <code>GradientPaint</code> and 185 * <code>TexturePaint</code> are not.</li> 186 * <li><code>CHAR_REPLACEMENT</code> uses 187 * <code>GraphicAttribute</code> values. The subclasses 188 * <code>ShapeGraphicAttribute</code> and 189 * <code>ImageGraphicAttribute</code> are not serializable.</li> 190 * <li><code>INPUT_METHOD_HIGHLIGHT</code> uses 191 * <code>InputMethodHighlight</code> values, which are 192 * not serializable. See {@link java.awt.im.InputMethodHighlight}.</li> 193 * </ul> 194 * 195 * <p>Clients who create custom subclasses of <code>Paint</code> and 196 * <code>GraphicAttribute</code> can make them serializable and 197 * avoid this problem. Clients who use input method highlights can 198 * convert these to the platform-specific attributes for that 199 * highlight on the current platform and set them on the Font as 200 * a workaround. 201 * 202 * <p>The <code>Map</code>-based constructor and 203 * <code>deriveFont</code> APIs ignore the FONT attribute, and it is 204 * not retained by the Font; the static {@link #getFont} method should 205 * be used if the FONT attribute might be present. See {@link 206 * java.awt.font.TextAttribute#FONT} for more information.</p> 207 * 208 * <p>Several attributes will cause additional rendering overhead 209 * and potentially invoke layout. If a <code>Font</code> has such 210 * attributes, the <code>{@link #hasLayoutAttributes()}</code> method 211 * will return true.</p> 212 * 213 * <p>Note: Font rotations can cause text baselines to be rotated. In 214 * order to account for this (rare) possibility, font APIs are 215 * specified to return metrics and take parameters 'in 216 * baseline-relative coordinates'. This maps the 'x' coordinate to 217 * the advance along the baseline, (positive x is forward along the 218 * baseline), and the 'y' coordinate to a distance along the 219 * perpendicular to the baseline at 'x' (positive y is 90 degrees 220 * clockwise from the baseline vector). APIs for which this is 221 * especially important are called out as having 'baseline-relative 222 * coordinates.' 223 */ 224 public class Font implements java.io.Serializable 225 { 226 private static class FontAccessImpl extends FontAccess { 227 public Font2D getFont2D(Font font) { 228 return font.getFont2D(); 229 } 230 231 public void setFont2D(Font font, Font2DHandle handle) { 232 font.font2DHandle = handle; 233 } 234 235 public void setCreatedFont(Font font) { 236 font.createdFont = true; 237 } 238 239 public boolean isCreatedFont(Font font) { 240 return font.createdFont; 241 } 242 } 243 244 static { 245 /* ensure that the necessary native libraries are loaded */ 246 Toolkit.loadLibraries(); 247 initIDs(); 248 FontAccess.setFontAccess(new FontAccessImpl()); 249 } 250 251 /** 252 * This is now only used during serialization. Typically 253 * it is null. 254 * 255 * @serial 256 * @see #getAttributes() 257 */ 258 private Hashtable<Object, Object> fRequestedAttributes; 259 260 /* 261 * Constants to be used for logical font family names. 262 */ 263 264 /** 265 * A String constant for the canonical family name of the 266 * logical font "Dialog". It is useful in Font construction 267 * to provide compile-time verification of the name. 268 * @since 1.6 269 */ 270 public static final String DIALOG = "Dialog"; 271 272 /** 273 * A String constant for the canonical family name of the 274 * logical font "DialogInput". It is useful in Font construction 275 * to provide compile-time verification of the name. 276 * @since 1.6 277 */ 278 public static final String DIALOG_INPUT = "DialogInput"; 279 280 /** 281 * A String constant for the canonical family name of the 282 * logical font "SansSerif". It is useful in Font construction 283 * to provide compile-time verification of the name. 284 * @since 1.6 285 */ 286 public static final String SANS_SERIF = "SansSerif"; 287 288 /** 289 * A String constant for the canonical family name of the 290 * logical font "Serif". It is useful in Font construction 291 * to provide compile-time verification of the name. 292 * @since 1.6 293 */ 294 public static final String SERIF = "Serif"; 295 296 /** 297 * A String constant for the canonical family name of the 298 * logical font "Monospaced". It is useful in Font construction 299 * to provide compile-time verification of the name. 300 * @since 1.6 301 */ 302 public static final String MONOSPACED = "Monospaced"; 303 304 /* 305 * Constants to be used for styles. Can be combined to mix 306 * styles. 307 */ 308 309 /** 310 * The plain style constant. 311 */ 312 public static final int PLAIN = 0; 313 314 /** 315 * The bold style constant. This can be combined with the other style 316 * constants (except PLAIN) for mixed styles. 317 */ 318 public static final int BOLD = 1; 319 320 /** 321 * The italicized style constant. This can be combined with the other 322 * style constants (except PLAIN) for mixed styles. 323 */ 324 public static final int ITALIC = 2; 325 326 /** 327 * The baseline used in most Roman scripts when laying out text. 328 */ 329 public static final int ROMAN_BASELINE = 0; 330 331 /** 332 * The baseline used in ideographic scripts like Chinese, Japanese, 333 * and Korean when laying out text. 334 */ 335 public static final int CENTER_BASELINE = 1; 336 337 /** 338 * The baseline used in Devanigiri and similar scripts when laying 339 * out text. 340 */ 341 public static final int HANGING_BASELINE = 2; 342 343 /** 344 * Identify a font resource of type TRUETYPE. 345 * Used to specify a TrueType font resource to the 346 * {@link #createFont} method. 347 * The TrueType format was extended to become the OpenType 348 * format, which adds support for fonts with Postscript outlines, 349 * this tag therefore references these fonts, as well as those 350 * with TrueType outlines. 351 * @since 1.3 352 */ 353 354 public static final int TRUETYPE_FONT = 0; 355 356 /** 357 * Identify a font resource of type TYPE1. 358 * Used to specify a Type1 font resource to the 359 * {@link #createFont} method. 360 * @since 1.5 361 */ 362 public static final int TYPE1_FONT = 1; 363 364 /** 365 * The logical name of this <code>Font</code>, as passed to the 366 * constructor. 367 * @since JDK1.0 368 * 369 * @serial 370 * @see #getName 371 */ 372 protected String name; 373 374 /** 375 * The style of this <code>Font</code>, as passed to the constructor. 376 * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC. 377 * @since JDK1.0 378 * 379 * @serial 380 * @see #getStyle() 381 */ 382 protected int style; 383 384 /** 385 * The point size of this <code>Font</code>, rounded to integer. 386 * @since JDK1.0 387 * 388 * @serial 389 * @see #getSize() 390 */ 391 protected int size; 392 393 /** 394 * The point size of this <code>Font</code> in <code>float</code>. 395 * 396 * @serial 397 * @see #getSize() 398 * @see #getSize2D() 399 */ 400 protected float pointSize; 401 402 /** 403 * The platform specific font information. 404 */ 405 private transient FontPeer peer; 406 private transient long pData; // native JDK1.1 font pointer 407 private transient Font2DHandle font2DHandle; 408 409 private transient AttributeValues values; 410 private transient boolean hasLayoutAttributes; 411 412 /* 413 * If the origin of a Font is a created font then this attribute 414 * must be set on all derived fonts too. 415 */ 416 private transient boolean createdFont = false; 417 418 /* 419 * This is true if the font transform is not identity. It 420 * is used to avoid unnecessary instantiation of an AffineTransform. 421 */ 422 private transient boolean nonIdentityTx; 423 424 /* 425 * A cached value used when a transform is required for internal 426 * use. This must not be exposed to callers since AffineTransform 427 * is mutable. 428 */ 429 private static final AffineTransform identityTx = new AffineTransform(); 430 431 /* 432 * JDK 1.1 serialVersionUID 433 */ 434 private static final long serialVersionUID = -4206021311591459213L; 435 436 /** 437 * Gets the peer of this <code>Font</code>. 438 * @return the peer of the <code>Font</code>. 439 * @since JDK1.1 440 * @deprecated Font rendering is now platform independent. 441 */ 442 @Deprecated 443 public FontPeer getPeer(){ 444 return getPeer_NoClientCode(); 445 } 446 // NOTE: This method is called by privileged threads. 447 // We implement this functionality in a package-private method 448 // to insure that it cannot be overridden by client subclasses. 449 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 450 @SuppressWarnings("deprecation") 451 final FontPeer getPeer_NoClientCode() { 452 if(peer == null) { 453 Toolkit tk = Toolkit.getDefaultToolkit(); 454 this.peer = tk.getFontPeer(name, style); 455 } 456 return peer; 457 } 458 459 /** 460 * Return the AttributeValues object associated with this 461 * font. Most of the time, the internal object is null. 462 * If required, it will be created from the 'standard' 463 * state on the font. Only non-default values will be 464 * set in the AttributeValues object. 465 * 466 * <p>Since the AttributeValues object is mutable, and it 467 * is cached in the font, care must be taken to ensure that 468 * it is not mutated. 469 */ 470 private AttributeValues getAttributeValues() { 471 if (values == null) { 472 AttributeValues valuesTmp = new AttributeValues(); 473 valuesTmp.setFamily(name); 474 valuesTmp.setSize(pointSize); // expects the float value. 475 476 if ((style & BOLD) != 0) { 477 valuesTmp.setWeight(2); // WEIGHT_BOLD 478 } 479 480 if ((style & ITALIC) != 0) { 481 valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE 482 } 483 valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility 484 values = valuesTmp; 485 } 486 487 return values; 488 } 489 490 private Font2D getFont2D() { 491 FontManager fm = FontManagerFactory.getInstance(); 492 if (fm.usingPerAppContextComposites() && 493 font2DHandle != null && 494 font2DHandle.font2D instanceof CompositeFont && 495 ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) { 496 return fm.findFont2D(name, style, 497 FontManager.LOGICAL_FALLBACK); 498 } else if (font2DHandle == null) { 499 font2DHandle = 500 fm.findFont2D(name, style, 501 FontManager.LOGICAL_FALLBACK).handle; 502 } 503 /* Do not cache the de-referenced font2D. It must be explicitly 504 * de-referenced to pick up a valid font in the event that the 505 * original one is marked invalid 506 */ 507 return font2DHandle.font2D; 508 } 509 510 /** 511 * Creates a new <code>Font</code> from the specified name, style and 512 * point size. 513 * <p> 514 * The font name can be a font face name or a font family name. 515 * It is used together with the style to find an appropriate font face. 516 * When a font family name is specified, the style argument is used to 517 * select the most appropriate face from the family. When a font face 518 * name is specified, the face's style and the style argument are 519 * merged to locate the best matching font from the same family. 520 * For example if face name "Arial Bold" is specified with style 521 * <code>Font.ITALIC</code>, the font system looks for a face in the 522 * "Arial" family that is bold and italic, and may associate the font 523 * instance with the physical font face "Arial Bold Italic". 524 * The style argument is merged with the specified face's style, not 525 * added or subtracted. 526 * This means, specifying a bold face and a bold style does not 527 * double-embolden the font, and specifying a bold face and a plain 528 * style does not lighten the font. 529 * <p> 530 * If no face for the requested style can be found, the font system 531 * may apply algorithmic styling to achieve the desired style. 532 * For example, if <code>ITALIC</code> is requested, but no italic 533 * face is available, glyphs from the plain face may be algorithmically 534 * obliqued (slanted). 535 * <p> 536 * Font name lookup is case insensitive, using the case folding 537 * rules of the US locale. 538 * <p> 539 * If the <code>name</code> parameter represents something other than a 540 * logical font, i.e. is interpreted as a physical font face or family, and 541 * this cannot be mapped by the implementation to a physical font or a 542 * compatible alternative, then the font system will map the Font 543 * instance to "Dialog", such that for example, the family as reported 544 * by {@link #getFamily() getFamily} will be "Dialog". 545 * 546 * @param name the font name. This can be a font face name or a font 547 * family name, and may represent either a logical font or a physical 548 * font found in this {@code GraphicsEnvironment}. 549 * The family names for logical fonts are: Dialog, DialogInput, 550 * Monospaced, Serif, or SansSerif. Pre-defined String constants exist 551 * for all of these names, for example, {@code DIALOG}. If {@code name} is 552 * {@code null}, the <em>logical font name</em> of the new 553 * {@code Font} as returned by {@code getName()} is set to 554 * the name "Default". 555 * @param style the style constant for the {@code Font} 556 * The style argument is an integer bitmask that may 557 * be {@code PLAIN}, or a bitwise union of {@code BOLD} and/or 558 * {@code ITALIC} (for example, {@code ITALIC} or {@code BOLD|ITALIC}). 559 * If the style argument does not conform to one of the expected 560 * integer bitmasks then the style is set to {@code PLAIN}. 561 * @param size the point size of the {@code Font} 562 * @see GraphicsEnvironment#getAllFonts 563 * @see GraphicsEnvironment#getAvailableFontFamilyNames 564 * @since JDK1.0 565 */ 566 public Font(String name, int style, int size) { 567 this.name = (name != null) ? name : "Default"; 568 this.style = (style & ~0x03) == 0 ? style : 0; 569 this.size = size; 570 this.pointSize = size; 571 } 572 573 private Font(String name, int style, float sizePts) { 574 this.name = (name != null) ? name : "Default"; 575 this.style = (style & ~0x03) == 0 ? style : 0; 576 this.size = (int)(sizePts + 0.5); 577 this.pointSize = sizePts; 578 } 579 580 /* This constructor is used by deriveFont when attributes is null */ 581 private Font(String name, int style, float sizePts, 582 boolean created, Font2DHandle handle) { 583 this(name, style, sizePts); 584 this.createdFont = created; 585 /* Fonts created from a stream will use the same font2D instance 586 * as the parent. 587 * One exception is that if the derived font is requested to be 588 * in a different style, then also check if its a CompositeFont 589 * and if so build a new CompositeFont from components of that style. 590 * CompositeFonts can only be marked as "created" if they are used 591 * to add fall backs to a physical font. And non-composites are 592 * always from "Font.createFont()" and shouldn't get this treatment. 593 */ 594 if (created) { 595 if (handle.font2D instanceof CompositeFont && 596 handle.font2D.getStyle() != style) { 597 FontManager fm = FontManagerFactory.getInstance(); 598 this.font2DHandle = fm.getNewComposite(null, style, handle); 599 } else { 600 this.font2DHandle = handle; 601 } 602 } 603 } 604 605 /* used to implement Font.createFont */ 606 private Font(File fontFile, int fontFormat, 607 boolean isCopy, CreatedFontTracker tracker) 608 throws FontFormatException { 609 this.createdFont = true; 610 /* Font2D instances created by this method track their font file 611 * so that when the Font2D is GC'd it can also remove the file. 612 */ 613 FontManager fm = FontManagerFactory.getInstance(); 614 this.font2DHandle = fm.createFont2D(fontFile, fontFormat, isCopy, 615 tracker).handle; 616 this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault()); 617 this.style = Font.PLAIN; 618 this.size = 1; 619 this.pointSize = 1f; 620 } 621 622 /* This constructor is used when one font is derived from another. 623 * Fonts created from a stream will use the same font2D instance as the 624 * parent. They can be distinguished because the "created" argument 625 * will be "true". Since there is no way to recreate these fonts they 626 * need to have the handle to the underlying font2D passed in. 627 * "created" is also true when a special composite is referenced by the 628 * handle for essentially the same reasons. 629 * But when deriving a font in these cases two particular attributes 630 * need special attention: family/face and style. 631 * The "composites" in these cases need to be recreated with optimal 632 * fonts for the new values of family and style. 633 * For fonts created with createFont() these are treated differently. 634 * JDK can often synthesise a different style (bold from plain 635 * for example). For fonts created with "createFont" this is a reasonable 636 * solution but its also possible (although rare) to derive a font with a 637 * different family attribute. In this case JDK needs 638 * to break the tie with the original Font2D and find a new Font. 639 * The oldName and oldStyle are supplied so they can be compared with 640 * what the Font2D and the values. To speed things along : 641 * oldName == null will be interpreted as the name is unchanged. 642 * oldStyle = -1 will be interpreted as the style is unchanged. 643 * In these cases there is no need to interrogate "values". 644 */ 645 private Font(AttributeValues values, String oldName, int oldStyle, 646 boolean created, Font2DHandle handle) { 647 648 this.createdFont = created; 649 if (created) { 650 this.font2DHandle = handle; 651 652 String newName = null; 653 if (oldName != null) { 654 newName = values.getFamily(); 655 if (oldName.equals(newName)) newName = null; 656 } 657 int newStyle = 0; 658 if (oldStyle == -1) { 659 newStyle = -1; 660 } else { 661 if (values.getWeight() >= 2f) newStyle = BOLD; 662 if (values.getPosture() >= .2f) newStyle |= ITALIC; 663 if (oldStyle == newStyle) newStyle = -1; 664 } 665 if (handle.font2D instanceof CompositeFont) { 666 if (newStyle != -1 || newName != null) { 667 FontManager fm = FontManagerFactory.getInstance(); 668 this.font2DHandle = 669 fm.getNewComposite(newName, newStyle, handle); 670 } 671 } else if (newName != null) { 672 this.createdFont = false; 673 this.font2DHandle = null; 674 } 675 } 676 initFromValues(values); 677 } 678 679 /** 680 * Creates a new <code>Font</code> with the specified attributes. 681 * Only keys defined in {@link java.awt.font.TextAttribute TextAttribute} 682 * are recognized. In addition the FONT attribute is 683 * not recognized by this constructor 684 * (see {@link #getAvailableAttributes}). Only attributes that have 685 * values of valid types will affect the new <code>Font</code>. 686 * <p> 687 * If <code>attributes</code> is <code>null</code>, a new 688 * <code>Font</code> is initialized with default values. 689 * @see java.awt.font.TextAttribute 690 * @param attributes the attributes to assign to the new 691 * <code>Font</code>, or <code>null</code> 692 */ 693 public Font(Map<? extends Attribute, ?> attributes) { 694 initFromValues(AttributeValues.fromMap(attributes, RECOGNIZED_MASK)); 695 } 696 697 /** 698 * Creates a new <code>Font</code> from the specified <code>font</code>. 699 * This constructor is intended for use by subclasses. 700 * @param font from which to create this <code>Font</code>. 701 * @throws NullPointerException if <code>font</code> is null 702 * @since 1.6 703 */ 704 protected Font(Font font) { 705 if (font.values != null) { 706 initFromValues(font.getAttributeValues().clone()); 707 } else { 708 this.name = font.name; 709 this.style = font.style; 710 this.size = font.size; 711 this.pointSize = font.pointSize; 712 } 713 this.font2DHandle = font.font2DHandle; 714 this.createdFont = font.createdFont; 715 } 716 717 /** 718 * Font recognizes all attributes except FONT. 719 */ 720 private static final int RECOGNIZED_MASK = AttributeValues.MASK_ALL 721 & ~AttributeValues.getMask(EFONT); 722 723 /** 724 * These attributes are considered primary by the FONT attribute. 725 */ 726 private static final int PRIMARY_MASK = 727 AttributeValues.getMask(EFAMILY, EWEIGHT, EWIDTH, EPOSTURE, ESIZE, 728 ETRANSFORM, ESUPERSCRIPT, ETRACKING); 729 730 /** 731 * These attributes are considered secondary by the FONT attribute. 732 */ 733 private static final int SECONDARY_MASK = 734 RECOGNIZED_MASK & ~PRIMARY_MASK; 735 736 /** 737 * These attributes are handled by layout. 738 */ 739 private static final int LAYOUT_MASK = 740 AttributeValues.getMask(ECHAR_REPLACEMENT, EFOREGROUND, EBACKGROUND, 741 EUNDERLINE, ESTRIKETHROUGH, ERUN_DIRECTION, 742 EBIDI_EMBEDDING, EJUSTIFICATION, 743 EINPUT_METHOD_HIGHLIGHT, EINPUT_METHOD_UNDERLINE, 744 ESWAP_COLORS, ENUMERIC_SHAPING, EKERNING, 745 ELIGATURES, ETRACKING, ESUPERSCRIPT); 746 747 private static final int EXTRA_MASK = 748 AttributeValues.getMask(ETRANSFORM, ESUPERSCRIPT, EWIDTH); 749 750 /** 751 * Initialize the standard Font fields from the values object. 752 */ 753 private void initFromValues(AttributeValues values) { 754 this.values = values; 755 values.defineAll(PRIMARY_MASK); // for 1.5 streaming compatibility 756 757 this.name = values.getFamily(); 758 this.pointSize = values.getSize(); 759 this.size = (int)(values.getSize() + 0.5); 760 if (values.getWeight() >= 2f) this.style |= BOLD; // not == 2f 761 if (values.getPosture() >= .2f) this.style |= ITALIC; // not == .2f 762 763 this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); 764 this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); 765 } 766 767 /** 768 * Returns a <code>Font</code> appropriate to the attributes. 769 * If <code>attributes</code>contains a <code>FONT</code> attribute 770 * with a valid <code>Font</code> as its value, it will be 771 * merged with any remaining attributes. See 772 * {@link java.awt.font.TextAttribute#FONT} for more 773 * information. 774 * 775 * @param attributes the attributes to assign to the new 776 * <code>Font</code> 777 * @return a new <code>Font</code> created with the specified 778 * attributes 779 * @throws NullPointerException if <code>attributes</code> is null. 780 * @since 1.2 781 * @see java.awt.font.TextAttribute 782 */ 783 public static Font getFont(Map<? extends Attribute, ?> attributes) { 784 // optimize for two cases: 785 // 1) FONT attribute, and nothing else 786 // 2) attributes, but no FONT 787 788 // avoid turning the attributemap into a regular map for no reason 789 if (attributes instanceof AttributeMap && 790 ((AttributeMap)attributes).getValues() != null) { 791 AttributeValues values = ((AttributeMap)attributes).getValues(); 792 if (values.isNonDefault(EFONT)) { 793 Font font = values.getFont(); 794 if (!values.anyDefined(SECONDARY_MASK)) { 795 return font; 796 } 797 // merge 798 values = font.getAttributeValues().clone(); 799 values.merge(attributes, SECONDARY_MASK); 800 return new Font(values, font.name, font.style, 801 font.createdFont, font.font2DHandle); 802 } 803 return new Font(attributes); 804 } 805 806 Font font = (Font)attributes.get(TextAttribute.FONT); 807 if (font != null) { 808 if (attributes.size() > 1) { // oh well, check for anything else 809 AttributeValues values = font.getAttributeValues().clone(); 810 values.merge(attributes, SECONDARY_MASK); 811 return new Font(values, font.name, font.style, 812 font.createdFont, font.font2DHandle); 813 } 814 815 return font; 816 } 817 818 return new Font(attributes); 819 } 820 821 /** 822 * Used with the byte count tracker for fonts created from streams. 823 * If a thread can create temp files anyway, no point in counting 824 * font bytes. 825 */ 826 private static boolean hasTempPermission() { 827 828 if (System.getSecurityManager() == null) { 829 return true; 830 } 831 File f = null; 832 boolean hasPerm = false; 833 try { 834 f = Files.createTempFile("+~JT", ".tmp").toFile(); 835 f.delete(); 836 f = null; 837 hasPerm = true; 838 } catch (Throwable t) { 839 /* inc. any kind of SecurityException */ 840 } 841 return hasPerm; 842 } 843 844 /** 845 * Returns a new <code>Font</code> using the specified font type 846 * and input data. The new <code>Font</code> is 847 * created with a point size of 1 and style {@link #PLAIN PLAIN}. 848 * This base font can then be used with the <code>deriveFont</code> 849 * methods in this class to derive new <code>Font</code> objects with 850 * varying sizes, styles, transforms and font features. This 851 * method does not close the {@link InputStream}. 852 * <p> 853 * To make the <code>Font</code> available to Font constructors the 854 * returned <code>Font</code> must be registered in the 855 * <code>GraphicsEnviroment</code> by calling 856 * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. 857 * @param fontFormat the type of the <code>Font</code>, which is 858 * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified. 859 * or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified. 860 * @param fontStream an <code>InputStream</code> object representing the 861 * input data for the font. 862 * @return a new <code>Font</code> created with the specified font type. 863 * @throws IllegalArgumentException if <code>fontFormat</code> is not 864 * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>. 865 * @throws FontFormatException if the <code>fontStream</code> data does 866 * not contain the required font tables for the specified format. 867 * @throws IOException if the <code>fontStream</code> 868 * cannot be completely read. 869 * @see GraphicsEnvironment#registerFont(Font) 870 * @since 1.3 871 */ 872 public static Font createFont(int fontFormat, InputStream fontStream) 873 throws java.awt.FontFormatException, java.io.IOException { 874 875 if (hasTempPermission()) { 876 return createFont0(fontFormat, fontStream, null); 877 } 878 879 // Otherwise, be extra conscious of pending temp file creation and 880 // resourcefully handle the temp file resources, among other things. 881 CreatedFontTracker tracker = CreatedFontTracker.getTracker(); 882 boolean acquired = false; 883 try { 884 acquired = tracker.acquirePermit(); 885 if (!acquired) { 886 throw new IOException("Timed out waiting for resources."); 887 } 888 return createFont0(fontFormat, fontStream, tracker); 889 } catch (InterruptedException e) { 890 throw new IOException("Problem reading font data."); 891 } finally { 892 if (acquired) { 893 tracker.releasePermit(); 894 } 895 } 896 } 897 898 private static Font createFont0(int fontFormat, InputStream fontStream, 899 CreatedFontTracker tracker) 900 throws java.awt.FontFormatException, java.io.IOException { 901 902 if (fontFormat != Font.TRUETYPE_FONT && 903 fontFormat != Font.TYPE1_FONT) { 904 throw new IllegalArgumentException ("font format not recognized"); 905 } 906 boolean copiedFontData = false; 907 try { 908 final File tFile = AccessController.doPrivileged( 909 new PrivilegedExceptionAction<File>() { 910 public File run() throws IOException { 911 return Files.createTempFile("+~JF", ".tmp").toFile(); 912 } 913 } 914 ); 915 if (tracker != null) { 916 tracker.add(tFile); 917 } 918 919 int totalSize = 0; 920 try { 921 final OutputStream outStream = 922 AccessController.doPrivileged( 923 new PrivilegedExceptionAction<OutputStream>() { 924 public OutputStream run() throws IOException { 925 return new FileOutputStream(tFile); 926 } 927 } 928 ); 929 if (tracker != null) { 930 tracker.set(tFile, outStream); 931 } 932 try { 933 byte[] buf = new byte[8192]; 934 for (;;) { 935 int bytesRead = fontStream.read(buf); 936 if (bytesRead < 0) { 937 break; 938 } 939 if (tracker != null) { 940 if (totalSize+bytesRead > CreatedFontTracker.MAX_FILE_SIZE) { 941 throw new IOException("File too big."); 942 } 943 if (totalSize+tracker.getNumBytes() > 944 CreatedFontTracker.MAX_TOTAL_BYTES) 945 { 946 throw new IOException("Total files too big."); 947 } 948 totalSize += bytesRead; 949 tracker.addBytes(bytesRead); 950 } 951 outStream.write(buf, 0, bytesRead); 952 } 953 /* don't close the input stream */ 954 } finally { 955 outStream.close(); 956 } 957 /* After all references to a Font2D are dropped, the file 958 * will be removed. To support long-lived AppContexts, 959 * we need to then decrement the byte count by the size 960 * of the file. 961 * If the data isn't a valid font, the implementation will 962 * delete the tmp file and decrement the byte count 963 * in the tracker object before returning from the 964 * constructor, so we can set 'copiedFontData' to true here 965 * without waiting for the results of that constructor. 966 */ 967 copiedFontData = true; 968 Font font = new Font(tFile, fontFormat, true, tracker); 969 return font; 970 } finally { 971 if (tracker != null) { 972 tracker.remove(tFile); 973 } 974 if (!copiedFontData) { 975 if (tracker != null) { 976 tracker.subBytes(totalSize); 977 } 978 AccessController.doPrivileged( 979 new PrivilegedExceptionAction<Void>() { 980 public Void run() { 981 tFile.delete(); 982 return null; 983 } 984 } 985 ); 986 } 987 } 988 } catch (Throwable t) { 989 if (t instanceof FontFormatException) { 990 throw (FontFormatException)t; 991 } 992 if (t instanceof IOException) { 993 throw (IOException)t; 994 } 995 Throwable cause = t.getCause(); 996 if (cause instanceof FontFormatException) { 997 throw (FontFormatException)cause; 998 } 999 throw new IOException("Problem reading font data."); 1000 } 1001 } 1002 1003 /** 1004 * Returns a new <code>Font</code> using the specified font type 1005 * and the specified font file. The new <code>Font</code> is 1006 * created with a point size of 1 and style {@link #PLAIN PLAIN}. 1007 * This base font can then be used with the <code>deriveFont</code> 1008 * methods in this class to derive new <code>Font</code> objects with 1009 * varying sizes, styles, transforms and font features. 1010 * @param fontFormat the type of the <code>Font</code>, which is 1011 * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is 1012 * specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is 1013 * specified. 1014 * So long as the returned font, or its derived fonts are referenced 1015 * the implementation may continue to access <code>fontFile</code> 1016 * to retrieve font data. Thus the results are undefined if the file 1017 * is changed, or becomes inaccessible. 1018 * <p> 1019 * To make the <code>Font</code> available to Font constructors the 1020 * returned <code>Font</code> must be registered in the 1021 * <code>GraphicsEnviroment</code> by calling 1022 * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. 1023 * @param fontFile a <code>File</code> object representing the 1024 * input data for the font. 1025 * @return a new <code>Font</code> created with the specified font type. 1026 * @throws IllegalArgumentException if <code>fontFormat</code> is not 1027 * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>. 1028 * @throws NullPointerException if <code>fontFile</code> is null. 1029 * @throws IOException if the <code>fontFile</code> cannot be read. 1030 * @throws FontFormatException if <code>fontFile</code> does 1031 * not contain the required font tables for the specified format. 1032 * @throws SecurityException if the executing code does not have 1033 * permission to read from the file. 1034 * @see GraphicsEnvironment#registerFont(Font) 1035 * @since 1.5 1036 */ 1037 public static Font createFont(int fontFormat, File fontFile) 1038 throws java.awt.FontFormatException, java.io.IOException { 1039 1040 fontFile = new File(fontFile.getPath()); 1041 1042 if (fontFormat != Font.TRUETYPE_FONT && 1043 fontFormat != Font.TYPE1_FONT) { 1044 throw new IllegalArgumentException ("font format not recognized"); 1045 } 1046 SecurityManager sm = System.getSecurityManager(); 1047 if (sm != null) { 1048 FilePermission filePermission = 1049 new FilePermission(fontFile.getPath(), "read"); 1050 sm.checkPermission(filePermission); 1051 } 1052 if (!fontFile.canRead()) { 1053 throw new IOException("Can't read " + fontFile); 1054 } 1055 return new Font(fontFile, fontFormat, false, null); 1056 } 1057 1058 /** 1059 * Returns a copy of the transform associated with this 1060 * <code>Font</code>. This transform is not necessarily the one 1061 * used to construct the font. If the font has algorithmic 1062 * superscripting or width adjustment, this will be incorporated 1063 * into the returned <code>AffineTransform</code>. 1064 * <p> 1065 * Typically, fonts will not be transformed. Clients generally 1066 * should call {@link #isTransformed} first, and only call this 1067 * method if <code>isTransformed</code> returns true. 1068 * 1069 * @return an {@link AffineTransform} object representing the 1070 * transform attribute of this <code>Font</code> object. 1071 */ 1072 public AffineTransform getTransform() { 1073 /* The most common case is the identity transform. Most callers 1074 * should call isTransformed() first, to decide if they need to 1075 * get the transform, but some may not. Here we check to see 1076 * if we have a nonidentity transform, and only do the work to 1077 * fetch and/or compute it if so, otherwise we return a new 1078 * identity transform. 1079 * 1080 * Note that the transform is _not_ necessarily the same as 1081 * the transform passed in as an Attribute in a Map, as the 1082 * transform returned will also reflect the effects of WIDTH and 1083 * SUPERSCRIPT attributes. Clients who want the actual transform 1084 * need to call getRequestedAttributes. 1085 */ 1086 if (nonIdentityTx) { 1087 AttributeValues values = getAttributeValues(); 1088 1089 AffineTransform at = values.isNonDefault(ETRANSFORM) 1090 ? new AffineTransform(values.getTransform()) 1091 : new AffineTransform(); 1092 1093 if (values.getSuperscript() != 0) { 1094 // can't get ascent and descent here, recursive call to this fn, 1095 // so use pointsize 1096 // let users combine super- and sub-scripting 1097 1098 int superscript = values.getSuperscript(); 1099 1100 double trans = 0; 1101 int n = 0; 1102 boolean up = superscript > 0; 1103 int sign = up ? -1 : 1; 1104 int ss = up ? superscript : -superscript; 1105 1106 while ((ss & 7) > n) { 1107 int newn = ss & 7; 1108 trans += sign * (ssinfo[newn] - ssinfo[n]); 1109 ss >>= 3; 1110 sign = -sign; 1111 n = newn; 1112 } 1113 trans *= pointSize; 1114 double scale = Math.pow(2./3., n); 1115 1116 at.preConcatenate(AffineTransform.getTranslateInstance(0, trans)); 1117 at.scale(scale, scale); 1118 1119 // note on placement and italics 1120 // We preconcatenate the transform because we don't want to translate along 1121 // the italic angle, but purely perpendicular to the baseline. While this 1122 // looks ok for superscripts, it can lead subscripts to stack on each other 1123 // and bring the following text too close. The way we deal with potential 1124 // collisions that can occur in the case of italics is by adjusting the 1125 // horizontal spacing of the adjacent glyphvectors. Examine the italic 1126 // angle of both vectors, if one is non-zero, compute the minimum ascent 1127 // and descent, and then the x position at each for each vector along its 1128 // italic angle starting from its (offset) baseline. Compute the difference 1129 // between the x positions and use the maximum difference to adjust the 1130 // position of the right gv. 1131 } 1132 1133 if (values.isNonDefault(EWIDTH)) { 1134 at.scale(values.getWidth(), 1f); 1135 } 1136 1137 return at; 1138 } 1139 1140 return new AffineTransform(); 1141 } 1142 1143 // x = r^0 + r^1 + r^2... r^n 1144 // rx = r^1 + r^2 + r^3... r^(n+1) 1145 // x - rx = r^0 - r^(n+1) 1146 // x (1 - r) = r^0 - r^(n+1) 1147 // x = (r^0 - r^(n+1)) / (1 - r) 1148 // x = (1 - r^(n+1)) / (1 - r) 1149 1150 // scale ratio is 2/3 1151 // trans = 1/2 of ascent * x 1152 // assume ascent is 3/4 of point size 1153 1154 private static final float[] ssinfo = { 1155 0.0f, 1156 0.375f, 1157 0.625f, 1158 0.7916667f, 1159 0.9027778f, 1160 0.9768519f, 1161 1.0262346f, 1162 1.0591564f, 1163 }; 1164 1165 /** 1166 * Returns the family name of this <code>Font</code>. 1167 * 1168 * <p>The family name of a font is font specific. Two fonts such as 1169 * Helvetica Italic and Helvetica Bold have the same family name, 1170 * <i>Helvetica</i>, whereas their font face names are 1171 * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of 1172 * available family names may be obtained by using the 1173 * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. 1174 * 1175 * <p>Use <code>getName</code> to get the logical name of the font. 1176 * Use <code>getFontName</code> to get the font face name of the font. 1177 * @return a <code>String</code> that is the family name of this 1178 * <code>Font</code>. 1179 * 1180 * @see #getName 1181 * @see #getFontName 1182 * @since JDK1.1 1183 */ 1184 public String getFamily() { 1185 return getFamily_NoClientCode(); 1186 } 1187 // NOTE: This method is called by privileged threads. 1188 // We implement this functionality in a package-private 1189 // method to insure that it cannot be overridden by client 1190 // subclasses. 1191 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 1192 final String getFamily_NoClientCode() { 1193 return getFamily(Locale.getDefault()); 1194 } 1195 1196 /** 1197 * Returns the family name of this <code>Font</code>, localized for 1198 * the specified locale. 1199 * 1200 * <p>The family name of a font is font specific. Two fonts such as 1201 * Helvetica Italic and Helvetica Bold have the same family name, 1202 * <i>Helvetica</i>, whereas their font face names are 1203 * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of 1204 * available family names may be obtained by using the 1205 * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. 1206 * 1207 * <p>Use <code>getFontName</code> to get the font face name of the font. 1208 * @param l locale for which to get the family name 1209 * @return a <code>String</code> representing the family name of the 1210 * font, localized for the specified locale. 1211 * @see #getFontName 1212 * @see java.util.Locale 1213 * @since 1.2 1214 */ 1215 public String getFamily(Locale l) { 1216 if (l == null) { 1217 throw new NullPointerException("null locale doesn't mean default"); 1218 } 1219 return getFont2D().getFamilyName(l); 1220 } 1221 1222 /** 1223 * Returns the postscript name of this <code>Font</code>. 1224 * Use <code>getFamily</code> to get the family name of the font. 1225 * Use <code>getFontName</code> to get the font face name of the font. 1226 * @return a <code>String</code> representing the postscript name of 1227 * this <code>Font</code>. 1228 * @since 1.2 1229 */ 1230 public String getPSName() { 1231 return getFont2D().getPostscriptName(); 1232 } 1233 1234 /** 1235 * Returns the logical name of this <code>Font</code>. 1236 * Use <code>getFamily</code> to get the family name of the font. 1237 * Use <code>getFontName</code> to get the font face name of the font. 1238 * @return a <code>String</code> representing the logical name of 1239 * this <code>Font</code>. 1240 * @see #getFamily 1241 * @see #getFontName 1242 * @since JDK1.0 1243 */ 1244 public String getName() { 1245 return name; 1246 } 1247 1248 /** 1249 * Returns the font face name of this <code>Font</code>. For example, 1250 * Helvetica Bold could be returned as a font face name. 1251 * Use <code>getFamily</code> to get the family name of the font. 1252 * Use <code>getName</code> to get the logical name of the font. 1253 * @return a <code>String</code> representing the font face name of 1254 * this <code>Font</code>. 1255 * @see #getFamily 1256 * @see #getName 1257 * @since 1.2 1258 */ 1259 public String getFontName() { 1260 return getFontName(Locale.getDefault()); 1261 } 1262 1263 /** 1264 * Returns the font face name of the <code>Font</code>, localized 1265 * for the specified locale. For example, Helvetica Fett could be 1266 * returned as the font face name. 1267 * Use <code>getFamily</code> to get the family name of the font. 1268 * @param l a locale for which to get the font face name 1269 * @return a <code>String</code> representing the font face name, 1270 * localized for the specified locale. 1271 * @see #getFamily 1272 * @see java.util.Locale 1273 */ 1274 public String getFontName(Locale l) { 1275 if (l == null) { 1276 throw new NullPointerException("null locale doesn't mean default"); 1277 } 1278 return getFont2D().getFontName(l); 1279 } 1280 1281 /** 1282 * Returns the style of this <code>Font</code>. The style can be 1283 * PLAIN, BOLD, ITALIC, or BOLD+ITALIC. 1284 * @return the style of this <code>Font</code> 1285 * @see #isPlain 1286 * @see #isBold 1287 * @see #isItalic 1288 * @since JDK1.0 1289 */ 1290 public int getStyle() { 1291 return style; 1292 } 1293 1294 /** 1295 * Returns the point size of this <code>Font</code>, rounded to 1296 * an integer. 1297 * Most users are familiar with the idea of using <i>point size</i> to 1298 * specify the size of glyphs in a font. This point size defines a 1299 * measurement between the baseline of one line to the baseline of the 1300 * following line in a single spaced text document. The point size is 1301 * based on <i>typographic points</i>, approximately 1/72 of an inch. 1302 * <p> 1303 * The Java(tm)2D API adopts the convention that one point is 1304 * equivalent to one unit in user coordinates. When using a 1305 * normalized transform for converting user space coordinates to 1306 * device space coordinates 72 user 1307 * space units equal 1 inch in device space. In this case one point 1308 * is 1/72 of an inch. 1309 * @return the point size of this <code>Font</code> in 1/72 of an 1310 * inch units. 1311 * @see #getSize2D 1312 * @see GraphicsConfiguration#getDefaultTransform 1313 * @see GraphicsConfiguration#getNormalizingTransform 1314 * @since JDK1.0 1315 */ 1316 public int getSize() { 1317 return size; 1318 } 1319 1320 /** 1321 * Returns the point size of this <code>Font</code> in 1322 * <code>float</code> value. 1323 * @return the point size of this <code>Font</code> as a 1324 * <code>float</code> value. 1325 * @see #getSize 1326 * @since 1.2 1327 */ 1328 public float getSize2D() { 1329 return pointSize; 1330 } 1331 1332 /** 1333 * Indicates whether or not this <code>Font</code> object's style is 1334 * PLAIN. 1335 * @return <code>true</code> if this <code>Font</code> has a 1336 * PLAIN style; 1337 * <code>false</code> otherwise. 1338 * @see java.awt.Font#getStyle 1339 * @since JDK1.0 1340 */ 1341 public boolean isPlain() { 1342 return style == 0; 1343 } 1344 1345 /** 1346 * Indicates whether or not this <code>Font</code> object's style is 1347 * BOLD. 1348 * @return <code>true</code> if this <code>Font</code> object's 1349 * style is BOLD; 1350 * <code>false</code> otherwise. 1351 * @see java.awt.Font#getStyle 1352 * @since JDK1.0 1353 */ 1354 public boolean isBold() { 1355 return (style & BOLD) != 0; 1356 } 1357 1358 /** 1359 * Indicates whether or not this <code>Font</code> object's style is 1360 * ITALIC. 1361 * @return <code>true</code> if this <code>Font</code> object's 1362 * style is ITALIC; 1363 * <code>false</code> otherwise. 1364 * @see java.awt.Font#getStyle 1365 * @since JDK1.0 1366 */ 1367 public boolean isItalic() { 1368 return (style & ITALIC) != 0; 1369 } 1370 1371 /** 1372 * Indicates whether or not this <code>Font</code> object has a 1373 * transform that affects its size in addition to the Size 1374 * attribute. 1375 * @return <code>true</code> if this <code>Font</code> object 1376 * has a non-identity AffineTransform attribute. 1377 * <code>false</code> otherwise. 1378 * @see java.awt.Font#getTransform 1379 * @since 1.4 1380 */ 1381 public boolean isTransformed() { 1382 return nonIdentityTx; 1383 } 1384 1385 /** 1386 * Return true if this Font contains attributes that require extra 1387 * layout processing. 1388 * @return true if the font has layout attributes 1389 * @since 1.6 1390 */ 1391 public boolean hasLayoutAttributes() { 1392 return hasLayoutAttributes; 1393 } 1394 1395 /** 1396 * Returns a <code>Font</code> object from the system properties list. 1397 * <code>nm</code> is treated as the name of a system property to be 1398 * obtained. The <code>String</code> value of this property is then 1399 * interpreted as a <code>Font</code> object according to the 1400 * specification of <code>Font.decode(String)</code> 1401 * If the specified property is not found, or the executing code does 1402 * not have permission to read the property, null is returned instead. 1403 * 1404 * @param nm the property name 1405 * @return a <code>Font</code> object that the property name 1406 * describes, or null if no such property exists. 1407 * @throws NullPointerException if nm is null. 1408 * @since 1.2 1409 * @see #decode(String) 1410 */ 1411 public static Font getFont(String nm) { 1412 return getFont(nm, null); 1413 } 1414 1415 /** 1416 * Returns the <code>Font</code> that the <code>str</code> 1417 * argument describes. 1418 * To ensure that this method returns the desired Font, 1419 * format the <code>str</code> parameter in 1420 * one of these ways 1421 * 1422 * <ul> 1423 * <li><em>fontname-style-pointsize</em> 1424 * <li><em>fontname-pointsize</em> 1425 * <li><em>fontname-style</em> 1426 * <li><em>fontname</em> 1427 * <li><em>fontname style pointsize</em> 1428 * <li><em>fontname pointsize</em> 1429 * <li><em>fontname style</em> 1430 * <li><em>fontname</em> 1431 * </ul> 1432 * in which <i>style</i> is one of the four 1433 * case-insensitive strings: 1434 * <code>"PLAIN"</code>, <code>"BOLD"</code>, <code>"BOLDITALIC"</code>, or 1435 * <code>"ITALIC"</code>, and pointsize is a positive decimal integer 1436 * representation of the point size. 1437 * For example, if you want a font that is Arial, bold, with 1438 * a point size of 18, you would call this method with: 1439 * "Arial-BOLD-18". 1440 * This is equivalent to calling the Font constructor : 1441 * <code>new Font("Arial", Font.BOLD, 18);</code> 1442 * and the values are interpreted as specified by that constructor. 1443 * <p> 1444 * A valid trailing decimal field is always interpreted as the pointsize. 1445 * Therefore a fontname containing a trailing decimal value should not 1446 * be used in the fontname only form. 1447 * <p> 1448 * If a style name field is not one of the valid style strings, it is 1449 * interpreted as part of the font name, and the default style is used. 1450 * <p> 1451 * Only one of ' ' or '-' may be used to separate fields in the input. 1452 * The identified separator is the one closest to the end of the string 1453 * which separates a valid pointsize, or a valid style name from 1454 * the rest of the string. 1455 * Null (empty) pointsize and style fields are treated 1456 * as valid fields with the default value for that field. 1457 *<p> 1458 * Some font names may include the separator characters ' ' or '-'. 1459 * If <code>str</code> is not formed with 3 components, e.g. such that 1460 * <code>style</code> or <code>pointsize</code> fields are not present in 1461 * <code>str</code>, and <code>fontname</code> also contains a 1462 * character determined to be the separator character 1463 * then these characters where they appear as intended to be part of 1464 * <code>fontname</code> may instead be interpreted as separators 1465 * so the font name may not be properly recognised. 1466 * 1467 * <p> 1468 * The default size is 12 and the default style is PLAIN. 1469 * If <code>str</code> does not specify a valid size, the returned 1470 * <code>Font</code> has a size of 12. If <code>str</code> does not 1471 * specify a valid style, the returned Font has a style of PLAIN. 1472 * If you do not specify a valid font name in 1473 * the <code>str</code> argument, this method will return 1474 * a font with the family name "Dialog". 1475 * To determine what font family names are available on 1476 * your system, use the 1477 * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. 1478 * If <code>str</code> is <code>null</code>, a new <code>Font</code> 1479 * is returned with the family name "Dialog", a size of 12 and a 1480 * PLAIN style. 1481 * @param str the name of the font, or <code>null</code> 1482 * @return the <code>Font</code> object that <code>str</code> 1483 * describes, or a new default <code>Font</code> if 1484 * <code>str</code> is <code>null</code>. 1485 * @see #getFamily 1486 * @since JDK1.1 1487 */ 1488 public static Font decode(String str) { 1489 String fontName = str; 1490 String styleName = ""; 1491 int fontSize = 12; 1492 int fontStyle = Font.PLAIN; 1493 1494 if (str == null) { 1495 return new Font(DIALOG, fontStyle, fontSize); 1496 } 1497 1498 int lastHyphen = str.lastIndexOf('-'); 1499 int lastSpace = str.lastIndexOf(' '); 1500 char sepChar = (lastHyphen > lastSpace) ? '-' : ' '; 1501 int sizeIndex = str.lastIndexOf(sepChar); 1502 int styleIndex = str.lastIndexOf(sepChar, sizeIndex-1); 1503 int strlen = str.length(); 1504 1505 if (sizeIndex > 0 && sizeIndex+1 < strlen) { 1506 try { 1507 fontSize = 1508 Integer.valueOf(str.substring(sizeIndex+1)).intValue(); 1509 if (fontSize <= 0) { 1510 fontSize = 12; 1511 } 1512 } catch (NumberFormatException e) { 1513 /* It wasn't a valid size, if we didn't also find the 1514 * start of the style string perhaps this is the style */ 1515 styleIndex = sizeIndex; 1516 sizeIndex = strlen; 1517 if (str.charAt(sizeIndex-1) == sepChar) { 1518 sizeIndex--; 1519 } 1520 } 1521 } 1522 1523 if (styleIndex >= 0 && styleIndex+1 < strlen) { 1524 styleName = str.substring(styleIndex+1, sizeIndex); 1525 styleName = styleName.toLowerCase(Locale.ENGLISH); 1526 if (styleName.equals("bolditalic")) { 1527 fontStyle = Font.BOLD | Font.ITALIC; 1528 } else if (styleName.equals("italic")) { 1529 fontStyle = Font.ITALIC; 1530 } else if (styleName.equals("bold")) { 1531 fontStyle = Font.BOLD; 1532 } else if (styleName.equals("plain")) { 1533 fontStyle = Font.PLAIN; 1534 } else { 1535 /* this string isn't any of the expected styles, so 1536 * assume its part of the font name 1537 */ 1538 styleIndex = sizeIndex; 1539 if (str.charAt(styleIndex-1) == sepChar) { 1540 styleIndex--; 1541 } 1542 } 1543 fontName = str.substring(0, styleIndex); 1544 1545 } else { 1546 int fontEnd = strlen; 1547 if (styleIndex > 0) { 1548 fontEnd = styleIndex; 1549 } else if (sizeIndex > 0) { 1550 fontEnd = sizeIndex; 1551 } 1552 if (fontEnd > 0 && str.charAt(fontEnd-1) == sepChar) { 1553 fontEnd--; 1554 } 1555 fontName = str.substring(0, fontEnd); 1556 } 1557 1558 return new Font(fontName, fontStyle, fontSize); 1559 } 1560 1561 /** 1562 * Gets the specified <code>Font</code> from the system properties 1563 * list. As in the <code>getProperty</code> method of 1564 * <code>System</code>, the first 1565 * argument is treated as the name of a system property to be 1566 * obtained. The <code>String</code> value of this property is then 1567 * interpreted as a <code>Font</code> object. 1568 * <p> 1569 * The property value should be one of the forms accepted by 1570 * <code>Font.decode(String)</code> 1571 * If the specified property is not found, or the executing code does not 1572 * have permission to read the property, the <code>font</code> 1573 * argument is returned instead. 1574 * @param nm the case-insensitive property name 1575 * @param font a default <code>Font</code> to return if property 1576 * <code>nm</code> is not defined 1577 * @return the <code>Font</code> value of the property. 1578 * @throws NullPointerException if nm is null. 1579 * @see #decode(String) 1580 */ 1581 public static Font getFont(String nm, Font font) { 1582 String str = null; 1583 try { 1584 str =System.getProperty(nm); 1585 } catch(SecurityException e) { 1586 } 1587 if (str == null) { 1588 return font; 1589 } 1590 return decode ( str ); 1591 } 1592 1593 transient int hash; 1594 /** 1595 * Returns a hashcode for this <code>Font</code>. 1596 * @return a hashcode value for this <code>Font</code>. 1597 * @since JDK1.0 1598 */ 1599 public int hashCode() { 1600 if (hash == 0) { 1601 hash = name.hashCode() ^ style ^ size; 1602 /* It is possible many fonts differ only in transform. 1603 * So include the transform in the hash calculation. 1604 * nonIdentityTx is set whenever there is a transform in 1605 * 'values'. The tests for null are required because it can 1606 * also be set for other reasons. 1607 */ 1608 if (nonIdentityTx && 1609 values != null && values.getTransform() != null) { 1610 hash ^= values.getTransform().hashCode(); 1611 } 1612 } 1613 return hash; 1614 } 1615 1616 /** 1617 * Compares this <code>Font</code> object to the specified 1618 * <code>Object</code>. 1619 * @param obj the <code>Object</code> to compare 1620 * @return <code>true</code> if the objects are the same 1621 * or if the argument is a <code>Font</code> object 1622 * describing the same font as this object; 1623 * <code>false</code> otherwise. 1624 * @since JDK1.0 1625 */ 1626 public boolean equals(Object obj) { 1627 if (obj == this) { 1628 return true; 1629 } 1630 1631 if (obj != null) { 1632 try { 1633 Font font = (Font)obj; 1634 if (size == font.size && 1635 style == font.style && 1636 nonIdentityTx == font.nonIdentityTx && 1637 hasLayoutAttributes == font.hasLayoutAttributes && 1638 pointSize == font.pointSize && 1639 name.equals(font.name)) { 1640 1641 /* 'values' is usually initialized lazily, except when 1642 * the font is constructed from a Map, or derived using 1643 * a Map or other values. So if only one font has 1644 * the field initialized we need to initialize it in 1645 * the other instance and compare. 1646 */ 1647 if (values == null) { 1648 if (font.values == null) { 1649 return true; 1650 } else { 1651 return getAttributeValues().equals(font.values); 1652 } 1653 } else { 1654 return values.equals(font.getAttributeValues()); 1655 } 1656 } 1657 } 1658 catch (ClassCastException e) { 1659 } 1660 } 1661 return false; 1662 } 1663 1664 /** 1665 * Converts this <code>Font</code> object to a <code>String</code> 1666 * representation. 1667 * @return a <code>String</code> representation of this 1668 * <code>Font</code> object. 1669 * @since JDK1.0 1670 */ 1671 // NOTE: This method may be called by privileged threads. 1672 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 1673 public String toString() { 1674 String strStyle; 1675 1676 if (isBold()) { 1677 strStyle = isItalic() ? "bolditalic" : "bold"; 1678 } else { 1679 strStyle = isItalic() ? "italic" : "plain"; 1680 } 1681 1682 return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" + 1683 strStyle + ",size=" + size + "]"; 1684 } // toString() 1685 1686 1687 /** Serialization support. A <code>readObject</code> 1688 * method is neccessary because the constructor creates 1689 * the font's peer, and we can't serialize the peer. 1690 * Similarly the computed font "family" may be different 1691 * at <code>readObject</code> time than at 1692 * <code>writeObject</code> time. An integer version is 1693 * written so that future versions of this class will be 1694 * able to recognize serialized output from this one. 1695 */ 1696 /** 1697 * The <code>Font</code> Serializable Data Form. 1698 * 1699 * @serial 1700 */ 1701 private int fontSerializedDataVersion = 1; 1702 1703 /** 1704 * Writes default serializable fields to a stream. 1705 * 1706 * @param s the <code>ObjectOutputStream</code> to write 1707 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 1708 * @see #readObject(java.io.ObjectInputStream) 1709 */ 1710 private void writeObject(java.io.ObjectOutputStream s) 1711 throws java.lang.ClassNotFoundException, 1712 java.io.IOException 1713 { 1714 if (values != null) { 1715 synchronized(values) { 1716 // transient 1717 fRequestedAttributes = values.toSerializableHashtable(); 1718 s.defaultWriteObject(); 1719 fRequestedAttributes = null; 1720 } 1721 } else { 1722 s.defaultWriteObject(); 1723 } 1724 } 1725 1726 /** 1727 * Reads the <code>ObjectInputStream</code>. 1728 * Unrecognized keys or values will be ignored. 1729 * 1730 * @param s the <code>ObjectInputStream</code> to read 1731 * @serial 1732 * @see #writeObject(java.io.ObjectOutputStream) 1733 */ 1734 private void readObject(java.io.ObjectInputStream s) 1735 throws java.lang.ClassNotFoundException, 1736 java.io.IOException 1737 { 1738 s.defaultReadObject(); 1739 if (pointSize == 0) { 1740 pointSize = (float)size; 1741 } 1742 1743 // Handle fRequestedAttributes. 1744 // in 1.5, we always streamed out the font values plus 1745 // TRANSFORM, SUPERSCRIPT, and WIDTH, regardless of whether the 1746 // values were default or not. In 1.6 we only stream out 1747 // defined values. So, 1.6 streams in from a 1.5 stream, 1748 // it check each of these values and 'undefines' it if the 1749 // value is the default. 1750 1751 if (fRequestedAttributes != null) { 1752 values = getAttributeValues(); // init 1753 AttributeValues extras = 1754 AttributeValues.fromSerializableHashtable(fRequestedAttributes); 1755 if (!AttributeValues.is16Hashtable(fRequestedAttributes)) { 1756 extras.unsetDefault(); // if legacy stream, undefine these 1757 } 1758 values = getAttributeValues().merge(extras); 1759 this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); 1760 this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); 1761 1762 fRequestedAttributes = null; // don't need it any more 1763 } 1764 } 1765 1766 /** 1767 * Returns the number of glyphs in this <code>Font</code>. Glyph codes 1768 * for this <code>Font</code> range from 0 to 1769 * <code>getNumGlyphs()</code> - 1. 1770 * @return the number of glyphs in this <code>Font</code>. 1771 * @since 1.2 1772 */ 1773 public int getNumGlyphs() { 1774 return getFont2D().getNumGlyphs(); 1775 } 1776 1777 /** 1778 * Returns the glyphCode which is used when this <code>Font</code> 1779 * does not have a glyph for a specified unicode code point. 1780 * @return the glyphCode of this <code>Font</code>. 1781 * @since 1.2 1782 */ 1783 public int getMissingGlyphCode() { 1784 return getFont2D().getMissingGlyphCode(); 1785 } 1786 1787 /** 1788 * Returns the baseline appropriate for displaying this character. 1789 * <p> 1790 * Large fonts can support different writing systems, and each system can 1791 * use a different baseline. 1792 * The character argument determines the writing system to use. Clients 1793 * should not assume all characters use the same baseline. 1794 * 1795 * @param c a character used to identify the writing system 1796 * @return the baseline appropriate for the specified character. 1797 * @see LineMetrics#getBaselineOffsets 1798 * @see #ROMAN_BASELINE 1799 * @see #CENTER_BASELINE 1800 * @see #HANGING_BASELINE 1801 * @since 1.2 1802 */ 1803 public byte getBaselineFor(char c) { 1804 return getFont2D().getBaselineFor(c); 1805 } 1806 1807 /** 1808 * Returns a map of font attributes available in this 1809 * <code>Font</code>. Attributes include things like ligatures and 1810 * glyph substitution. 1811 * @return the attributes map of this <code>Font</code>. 1812 */ 1813 public Map<TextAttribute,?> getAttributes(){ 1814 return new AttributeMap(getAttributeValues()); 1815 } 1816 1817 /** 1818 * Returns the keys of all the attributes supported by this 1819 * <code>Font</code>. These attributes can be used to derive other 1820 * fonts. 1821 * @return an array containing the keys of all the attributes 1822 * supported by this <code>Font</code>. 1823 * @since 1.2 1824 */ 1825 public Attribute[] getAvailableAttributes() { 1826 // FONT is not supported by Font 1827 1828 Attribute attributes[] = { 1829 TextAttribute.FAMILY, 1830 TextAttribute.WEIGHT, 1831 TextAttribute.WIDTH, 1832 TextAttribute.POSTURE, 1833 TextAttribute.SIZE, 1834 TextAttribute.TRANSFORM, 1835 TextAttribute.SUPERSCRIPT, 1836 TextAttribute.CHAR_REPLACEMENT, 1837 TextAttribute.FOREGROUND, 1838 TextAttribute.BACKGROUND, 1839 TextAttribute.UNDERLINE, 1840 TextAttribute.STRIKETHROUGH, 1841 TextAttribute.RUN_DIRECTION, 1842 TextAttribute.BIDI_EMBEDDING, 1843 TextAttribute.JUSTIFICATION, 1844 TextAttribute.INPUT_METHOD_HIGHLIGHT, 1845 TextAttribute.INPUT_METHOD_UNDERLINE, 1846 TextAttribute.SWAP_COLORS, 1847 TextAttribute.NUMERIC_SHAPING, 1848 TextAttribute.KERNING, 1849 TextAttribute.LIGATURES, 1850 TextAttribute.TRACKING, 1851 }; 1852 1853 return attributes; 1854 } 1855 1856 /** 1857 * Creates a new <code>Font</code> object by replicating this 1858 * <code>Font</code> object and applying a new style and size. 1859 * @param style the style for the new <code>Font</code> 1860 * @param size the size for the new <code>Font</code> 1861 * @return a new <code>Font</code> object. 1862 * @since 1.2 1863 */ 1864 public Font deriveFont(int style, float size){ 1865 if (values == null) { 1866 return new Font(name, style, size, createdFont, font2DHandle); 1867 } 1868 AttributeValues newValues = getAttributeValues().clone(); 1869 int oldStyle = (this.style != style) ? this.style : -1; 1870 applyStyle(style, newValues); 1871 newValues.setSize(size); 1872 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 1873 } 1874 1875 /** 1876 * Creates a new <code>Font</code> object by replicating this 1877 * <code>Font</code> object and applying a new style and transform. 1878 * @param style the style for the new <code>Font</code> 1879 * @param trans the <code>AffineTransform</code> associated with the 1880 * new <code>Font</code> 1881 * @return a new <code>Font</code> object. 1882 * @throws IllegalArgumentException if <code>trans</code> is 1883 * <code>null</code> 1884 * @since 1.2 1885 */ 1886 public Font deriveFont(int style, AffineTransform trans){ 1887 AttributeValues newValues = getAttributeValues().clone(); 1888 int oldStyle = (this.style != style) ? this.style : -1; 1889 applyStyle(style, newValues); 1890 applyTransform(trans, newValues); 1891 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 1892 } 1893 1894 /** 1895 * Creates a new <code>Font</code> object by replicating the current 1896 * <code>Font</code> object and applying a new size to it. 1897 * @param size the size for the new <code>Font</code>. 1898 * @return a new <code>Font</code> object. 1899 * @since 1.2 1900 */ 1901 public Font deriveFont(float size){ 1902 if (values == null) { 1903 return new Font(name, style, size, createdFont, font2DHandle); 1904 } 1905 AttributeValues newValues = getAttributeValues().clone(); 1906 newValues.setSize(size); 1907 return new Font(newValues, null, -1, createdFont, font2DHandle); 1908 } 1909 1910 /** 1911 * Creates a new <code>Font</code> object by replicating the current 1912 * <code>Font</code> object and applying a new transform to it. 1913 * @param trans the <code>AffineTransform</code> associated with the 1914 * new <code>Font</code> 1915 * @return a new <code>Font</code> object. 1916 * @throws IllegalArgumentException if <code>trans</code> is 1917 * <code>null</code> 1918 * @since 1.2 1919 */ 1920 public Font deriveFont(AffineTransform trans){ 1921 AttributeValues newValues = getAttributeValues().clone(); 1922 applyTransform(trans, newValues); 1923 return new Font(newValues, null, -1, createdFont, font2DHandle); 1924 } 1925 1926 /** 1927 * Creates a new <code>Font</code> object by replicating the current 1928 * <code>Font</code> object and applying a new style to it. 1929 * @param style the style for the new <code>Font</code> 1930 * @return a new <code>Font</code> object. 1931 * @since 1.2 1932 */ 1933 public Font deriveFont(int style){ 1934 if (values == null) { 1935 return new Font(name, style, size, createdFont, font2DHandle); 1936 } 1937 AttributeValues newValues = getAttributeValues().clone(); 1938 int oldStyle = (this.style != style) ? this.style : -1; 1939 applyStyle(style, newValues); 1940 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 1941 } 1942 1943 /** 1944 * Creates a new <code>Font</code> object by replicating the current 1945 * <code>Font</code> object and applying a new set of font attributes 1946 * to it. 1947 * 1948 * @param attributes a map of attributes enabled for the new 1949 * <code>Font</code> 1950 * @return a new <code>Font</code> object. 1951 * @since 1.2 1952 */ 1953 public Font deriveFont(Map<? extends Attribute, ?> attributes) { 1954 if (attributes == null) { 1955 return this; 1956 } 1957 AttributeValues newValues = getAttributeValues().clone(); 1958 newValues.merge(attributes, RECOGNIZED_MASK); 1959 1960 return new Font(newValues, name, style, createdFont, font2DHandle); 1961 } 1962 1963 /** 1964 * Checks if this <code>Font</code> has a glyph for the specified 1965 * character. 1966 * 1967 * <p> <b>Note:</b> This method cannot handle <a 1968 * href="../../java/lang/Character.html#supplementary"> supplementary 1969 * characters</a>. To support all Unicode characters, including 1970 * supplementary characters, use the {@link #canDisplay(int)} 1971 * method or <code>canDisplayUpTo</code> methods. 1972 * 1973 * @param c the character for which a glyph is needed 1974 * @return <code>true</code> if this <code>Font</code> has a glyph for this 1975 * character; <code>false</code> otherwise. 1976 * @since 1.2 1977 */ 1978 public boolean canDisplay(char c){ 1979 return getFont2D().canDisplay(c); 1980 } 1981 1982 /** 1983 * Checks if this <code>Font</code> has a glyph for the specified 1984 * character. 1985 * 1986 * @param codePoint the character (Unicode code point) for which a glyph 1987 * is needed. 1988 * @return <code>true</code> if this <code>Font</code> has a glyph for the 1989 * character; <code>false</code> otherwise. 1990 * @throws IllegalArgumentException if the code point is not a valid Unicode 1991 * code point. 1992 * @see Character#isValidCodePoint(int) 1993 * @since 1.5 1994 */ 1995 public boolean canDisplay(int codePoint) { 1996 if (!Character.isValidCodePoint(codePoint)) { 1997 throw new IllegalArgumentException("invalid code point: " + 1998 Integer.toHexString(codePoint)); 1999 } 2000 return getFont2D().canDisplay(codePoint); 2001 } 2002 2003 /** 2004 * Indicates whether or not this <code>Font</code> can display a 2005 * specified <code>String</code>. For strings with Unicode encoding, 2006 * it is important to know if a particular font can display the 2007 * string. This method returns an offset into the <code>String</code> 2008 * <code>str</code> which is the first character this 2009 * <code>Font</code> cannot display without using the missing glyph 2010 * code. If the <code>Font</code> can display all characters, -1 is 2011 * returned. 2012 * @param str a <code>String</code> object 2013 * @return an offset into <code>str</code> that points 2014 * to the first character in <code>str</code> that this 2015 * <code>Font</code> cannot display; or <code>-1</code> if 2016 * this <code>Font</code> can display all characters in 2017 * <code>str</code>. 2018 * @since 1.2 2019 */ 2020 public int canDisplayUpTo(String str) { 2021 Font2D font2d = getFont2D(); 2022 int len = str.length(); 2023 for (int i = 0; i < len; i++) { 2024 char c = str.charAt(i); 2025 if (font2d.canDisplay(c)) { 2026 continue; 2027 } 2028 if (!Character.isHighSurrogate(c)) { 2029 return i; 2030 } 2031 if (!font2d.canDisplay(str.codePointAt(i))) { 2032 return i; 2033 } 2034 i++; 2035 } 2036 return -1; 2037 } 2038 2039 /** 2040 * Indicates whether or not this <code>Font</code> can display 2041 * the characters in the specified <code>text</code> 2042 * starting at <code>start</code> and ending at 2043 * <code>limit</code>. This method is a convenience overload. 2044 * @param text the specified array of <code>char</code> values 2045 * @param start the specified starting offset (in 2046 * <code>char</code>s) into the specified array of 2047 * <code>char</code> values 2048 * @param limit the specified ending offset (in 2049 * <code>char</code>s) into the specified array of 2050 * <code>char</code> values 2051 * @return an offset into <code>text</code> that points 2052 * to the first character in <code>text</code> that this 2053 * <code>Font</code> cannot display; or <code>-1</code> if 2054 * this <code>Font</code> can display all characters in 2055 * <code>text</code>. 2056 * @since 1.2 2057 */ 2058 public int canDisplayUpTo(char[] text, int start, int limit) { 2059 Font2D font2d = getFont2D(); 2060 for (int i = start; i < limit; i++) { 2061 char c = text[i]; 2062 if (font2d.canDisplay(c)) { 2063 continue; 2064 } 2065 if (!Character.isHighSurrogate(c)) { 2066 return i; 2067 } 2068 if (!font2d.canDisplay(Character.codePointAt(text, i, limit))) { 2069 return i; 2070 } 2071 i++; 2072 } 2073 return -1; 2074 } 2075 2076 /** 2077 * Indicates whether or not this <code>Font</code> can display the 2078 * text specified by the <code>iter</code> starting at 2079 * <code>start</code> and ending at <code>limit</code>. 2080 * 2081 * @param iter a {@link CharacterIterator} object 2082 * @param start the specified starting offset into the specified 2083 * <code>CharacterIterator</code>. 2084 * @param limit the specified ending offset into the specified 2085 * <code>CharacterIterator</code>. 2086 * @return an offset into <code>iter</code> that points 2087 * to the first character in <code>iter</code> that this 2088 * <code>Font</code> cannot display; or <code>-1</code> if 2089 * this <code>Font</code> can display all characters in 2090 * <code>iter</code>. 2091 * @since 1.2 2092 */ 2093 public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { 2094 Font2D font2d = getFont2D(); 2095 char c = iter.setIndex(start); 2096 for (int i = start; i < limit; i++, c = iter.next()) { 2097 if (font2d.canDisplay(c)) { 2098 continue; 2099 } 2100 if (!Character.isHighSurrogate(c)) { 2101 return i; 2102 } 2103 char c2 = iter.next(); 2104 // c2 could be CharacterIterator.DONE which is not a low surrogate. 2105 if (!Character.isLowSurrogate(c2)) { 2106 return i; 2107 } 2108 if (!font2d.canDisplay(Character.toCodePoint(c, c2))) { 2109 return i; 2110 } 2111 i++; 2112 } 2113 return -1; 2114 } 2115 2116 /** 2117 * Returns the italic angle of this <code>Font</code>. The italic angle 2118 * is the inverse slope of the caret which best matches the posture of this 2119 * <code>Font</code>. 2120 * @see TextAttribute#POSTURE 2121 * @return the angle of the ITALIC style of this <code>Font</code>. 2122 */ 2123 public float getItalicAngle() { 2124 return getItalicAngle(null); 2125 } 2126 2127 /* The FRC hints don't affect the value of the italic angle but 2128 * we need to pass them in to look up a strike. 2129 * If we can pass in ones already being used it can prevent an extra 2130 * strike from being allocated. Note that since italic angle is 2131 * a property of the font, the font transform is needed not the 2132 * device transform. Finally, this is private but the only caller of this 2133 * in the JDK - and the only likely caller - is in this same class. 2134 */ 2135 private float getItalicAngle(FontRenderContext frc) { 2136 Object aa, fm; 2137 if (frc == null) { 2138 aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; 2139 fm = RenderingHints.VALUE_FRACTIONALMETRICS_OFF; 2140 } else { 2141 aa = frc.getAntiAliasingHint(); 2142 fm = frc.getFractionalMetricsHint(); 2143 } 2144 return getFont2D().getItalicAngle(this, identityTx, aa, fm); 2145 } 2146 2147 /** 2148 * Checks whether or not this <code>Font</code> has uniform 2149 * line metrics. A logical <code>Font</code> might be a 2150 * composite font, which means that it is composed of different 2151 * physical fonts to cover different code ranges. Each of these 2152 * fonts might have different <code>LineMetrics</code>. If the 2153 * logical <code>Font</code> is a single 2154 * font then the metrics would be uniform. 2155 * @return <code>true</code> if this <code>Font</code> has 2156 * uniform line metrics; <code>false</code> otherwise. 2157 */ 2158 public boolean hasUniformLineMetrics() { 2159 return false; // REMIND always safe, but prevents caller optimize 2160 } 2161 2162 private transient SoftReference<FontLineMetrics> flmref; 2163 private FontLineMetrics defaultLineMetrics(FontRenderContext frc) { 2164 FontLineMetrics flm = null; 2165 if (flmref == null 2166 || (flm = flmref.get()) == null 2167 || !flm.frc.equals(frc)) { 2168 2169 /* The device transform in the frc is not used in obtaining line 2170 * metrics, although it probably should be: REMIND find why not? 2171 * The font transform is used but its applied in getFontMetrics, so 2172 * just pass identity here 2173 */ 2174 float [] metrics = new float[8]; 2175 getFont2D().getFontMetrics(this, identityTx, 2176 frc.getAntiAliasingHint(), 2177 frc.getFractionalMetricsHint(), 2178 metrics); 2179 float ascent = metrics[0]; 2180 float descent = metrics[1]; 2181 float leading = metrics[2]; 2182 float ssOffset = 0; 2183 if (values != null && values.getSuperscript() != 0) { 2184 ssOffset = (float)getTransform().getTranslateY(); 2185 ascent -= ssOffset; 2186 descent += ssOffset; 2187 } 2188 float height = ascent + descent + leading; 2189 2190 int baselineIndex = 0; // need real index, assumes roman for everything 2191 // need real baselines eventually 2192 float[] baselineOffsets = { 0, (descent/2f - ascent) / 2f, -ascent }; 2193 2194 float strikethroughOffset = metrics[4]; 2195 float strikethroughThickness = metrics[5]; 2196 2197 float underlineOffset = metrics[6]; 2198 float underlineThickness = metrics[7]; 2199 2200 float italicAngle = getItalicAngle(frc); 2201 2202 if (isTransformed()) { 2203 AffineTransform ctx = values.getCharTransform(); // extract rotation 2204 if (ctx != null) { 2205 Point2D.Float pt = new Point2D.Float(); 2206 pt.setLocation(0, strikethroughOffset); 2207 ctx.deltaTransform(pt, pt); 2208 strikethroughOffset = pt.y; 2209 pt.setLocation(0, strikethroughThickness); 2210 ctx.deltaTransform(pt, pt); 2211 strikethroughThickness = pt.y; 2212 pt.setLocation(0, underlineOffset); 2213 ctx.deltaTransform(pt, pt); 2214 underlineOffset = pt.y; 2215 pt.setLocation(0, underlineThickness); 2216 ctx.deltaTransform(pt, pt); 2217 underlineThickness = pt.y; 2218 } 2219 } 2220 strikethroughOffset += ssOffset; 2221 underlineOffset += ssOffset; 2222 2223 CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height, 2224 baselineIndex, baselineOffsets, 2225 strikethroughOffset, strikethroughThickness, 2226 underlineOffset, underlineThickness, 2227 ssOffset, italicAngle); 2228 2229 flm = new FontLineMetrics(0, cm, frc); 2230 flmref = new SoftReference<FontLineMetrics>(flm); 2231 } 2232 2233 return (FontLineMetrics)flm.clone(); 2234 } 2235 2236 /** 2237 * Returns a {@link LineMetrics} object created with the specified 2238 * <code>String</code> and {@link FontRenderContext}. 2239 * @param str the specified <code>String</code> 2240 * @param frc the specified <code>FontRenderContext</code> 2241 * @return a <code>LineMetrics</code> object created with the 2242 * specified <code>String</code> and {@link FontRenderContext}. 2243 */ 2244 public LineMetrics getLineMetrics( String str, FontRenderContext frc) { 2245 FontLineMetrics flm = defaultLineMetrics(frc); 2246 flm.numchars = str.length(); 2247 return flm; 2248 } 2249 2250 /** 2251 * Returns a <code>LineMetrics</code> object created with the 2252 * specified arguments. 2253 * @param str the specified <code>String</code> 2254 * @param beginIndex the initial offset of <code>str</code> 2255 * @param limit the end offset of <code>str</code> 2256 * @param frc the specified <code>FontRenderContext</code> 2257 * @return a <code>LineMetrics</code> object created with the 2258 * specified arguments. 2259 */ 2260 public LineMetrics getLineMetrics( String str, 2261 int beginIndex, int limit, 2262 FontRenderContext frc) { 2263 FontLineMetrics flm = defaultLineMetrics(frc); 2264 int numChars = limit - beginIndex; 2265 flm.numchars = (numChars < 0)? 0: numChars; 2266 return flm; 2267 } 2268 2269 /** 2270 * Returns a <code>LineMetrics</code> object created with the 2271 * specified arguments. 2272 * @param chars an array of characters 2273 * @param beginIndex the initial offset of <code>chars</code> 2274 * @param limit the end offset of <code>chars</code> 2275 * @param frc the specified <code>FontRenderContext</code> 2276 * @return a <code>LineMetrics</code> object created with the 2277 * specified arguments. 2278 */ 2279 public LineMetrics getLineMetrics(char [] chars, 2280 int beginIndex, int limit, 2281 FontRenderContext frc) { 2282 FontLineMetrics flm = defaultLineMetrics(frc); 2283 int numChars = limit - beginIndex; 2284 flm.numchars = (numChars < 0)? 0: numChars; 2285 return flm; 2286 } 2287 2288 /** 2289 * Returns a <code>LineMetrics</code> object created with the 2290 * specified arguments. 2291 * @param ci the specified <code>CharacterIterator</code> 2292 * @param beginIndex the initial offset in <code>ci</code> 2293 * @param limit the end offset of <code>ci</code> 2294 * @param frc the specified <code>FontRenderContext</code> 2295 * @return a <code>LineMetrics</code> object created with the 2296 * specified arguments. 2297 */ 2298 public LineMetrics getLineMetrics(CharacterIterator ci, 2299 int beginIndex, int limit, 2300 FontRenderContext frc) { 2301 FontLineMetrics flm = defaultLineMetrics(frc); 2302 int numChars = limit - beginIndex; 2303 flm.numchars = (numChars < 0)? 0: numChars; 2304 return flm; 2305 } 2306 2307 /** 2308 * Returns the logical bounds of the specified <code>String</code> in 2309 * the specified <code>FontRenderContext</code>. The logical bounds 2310 * contains the origin, ascent, advance, and height, which includes 2311 * the leading. The logical bounds does not always enclose all the 2312 * text. For example, in some languages and in some fonts, accent 2313 * marks can be positioned above the ascent or below the descent. 2314 * To obtain a visual bounding box, which encloses all the text, 2315 * use the {@link TextLayout#getBounds() getBounds} method of 2316 * <code>TextLayout</code>. 2317 * <p>Note: The returned bounds is in baseline-relative coordinates 2318 * (see {@link java.awt.Font class notes}). 2319 * @param str the specified <code>String</code> 2320 * @param frc the specified <code>FontRenderContext</code> 2321 * @return a {@link Rectangle2D} that is the bounding box of the 2322 * specified <code>String</code> in the specified 2323 * <code>FontRenderContext</code>. 2324 * @see FontRenderContext 2325 * @see Font#createGlyphVector 2326 * @since 1.2 2327 */ 2328 public Rectangle2D getStringBounds( String str, FontRenderContext frc) { 2329 char[] array = str.toCharArray(); 2330 return getStringBounds(array, 0, array.length, frc); 2331 } 2332 2333 /** 2334 * Returns the logical bounds of the specified <code>String</code> in 2335 * the specified <code>FontRenderContext</code>. The logical bounds 2336 * contains the origin, ascent, advance, and height, which includes 2337 * the leading. The logical bounds does not always enclose all the 2338 * text. For example, in some languages and in some fonts, accent 2339 * marks can be positioned above the ascent or below the descent. 2340 * To obtain a visual bounding box, which encloses all the text, 2341 * use the {@link TextLayout#getBounds() getBounds} method of 2342 * <code>TextLayout</code>. 2343 * <p>Note: The returned bounds is in baseline-relative coordinates 2344 * (see {@link java.awt.Font class notes}). 2345 * @param str the specified <code>String</code> 2346 * @param beginIndex the initial offset of <code>str</code> 2347 * @param limit the end offset of <code>str</code> 2348 * @param frc the specified <code>FontRenderContext</code> 2349 * @return a <code>Rectangle2D</code> that is the bounding box of the 2350 * specified <code>String</code> in the specified 2351 * <code>FontRenderContext</code>. 2352 * @throws IndexOutOfBoundsException if <code>beginIndex</code> is 2353 * less than zero, or <code>limit</code> is greater than the 2354 * length of <code>str</code>, or <code>beginIndex</code> 2355 * is greater than <code>limit</code>. 2356 * @see FontRenderContext 2357 * @see Font#createGlyphVector 2358 * @since 1.2 2359 */ 2360 public Rectangle2D getStringBounds( String str, 2361 int beginIndex, int limit, 2362 FontRenderContext frc) { 2363 String substr = str.substring(beginIndex, limit); 2364 return getStringBounds(substr, frc); 2365 } 2366 2367 /** 2368 * Returns the logical bounds of the specified array of characters 2369 * in the specified <code>FontRenderContext</code>. The logical 2370 * bounds contains the origin, ascent, advance, and height, which 2371 * includes the leading. The logical bounds does not always enclose 2372 * all the text. For example, in some languages and in some fonts, 2373 * accent marks can be positioned above the ascent or below the 2374 * descent. To obtain a visual bounding box, which encloses all the 2375 * text, use the {@link TextLayout#getBounds() getBounds} method of 2376 * <code>TextLayout</code>. 2377 * <p>Note: The returned bounds is in baseline-relative coordinates 2378 * (see {@link java.awt.Font class notes}). 2379 * @param chars an array of characters 2380 * @param beginIndex the initial offset in the array of 2381 * characters 2382 * @param limit the end offset in the array of characters 2383 * @param frc the specified <code>FontRenderContext</code> 2384 * @return a <code>Rectangle2D</code> that is the bounding box of the 2385 * specified array of characters in the specified 2386 * <code>FontRenderContext</code>. 2387 * @throws IndexOutOfBoundsException if <code>beginIndex</code> is 2388 * less than zero, or <code>limit</code> is greater than the 2389 * length of <code>chars</code>, or <code>beginIndex</code> 2390 * is greater than <code>limit</code>. 2391 * @see FontRenderContext 2392 * @see Font#createGlyphVector 2393 * @since 1.2 2394 */ 2395 public Rectangle2D getStringBounds(char [] chars, 2396 int beginIndex, int limit, 2397 FontRenderContext frc) { 2398 if (beginIndex < 0) { 2399 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); 2400 } 2401 if (limit > chars.length) { 2402 throw new IndexOutOfBoundsException("limit: " + limit); 2403 } 2404 if (beginIndex > limit) { 2405 throw new IndexOutOfBoundsException("range length: " + 2406 (limit - beginIndex)); 2407 } 2408 2409 // this code should be in textlayout 2410 // quick check for simple text, assume GV ok to use if simple 2411 2412 boolean simple = values == null || 2413 (values.getKerning() == 0 && values.getLigatures() == 0 && 2414 values.getBaselineTransform() == null); 2415 if (simple) { 2416 simple = ! FontUtilities.isComplexText(chars, beginIndex, limit); 2417 } 2418 2419 if (simple) { 2420 GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex, 2421 limit - beginIndex, frc); 2422 return gv.getLogicalBounds(); 2423 } else { 2424 // need char array constructor on textlayout 2425 String str = new String(chars, beginIndex, limit - beginIndex); 2426 TextLayout tl = new TextLayout(str, this, frc); 2427 return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(), 2428 tl.getAscent() + tl.getDescent() + 2429 tl.getLeading()); 2430 } 2431 } 2432 2433 /** 2434 * Returns the logical bounds of the characters indexed in the 2435 * specified {@link CharacterIterator} in the 2436 * specified <code>FontRenderContext</code>. The logical bounds 2437 * contains the origin, ascent, advance, and height, which includes 2438 * the leading. The logical bounds does not always enclose all the 2439 * text. For example, in some languages and in some fonts, accent 2440 * marks can be positioned above the ascent or below the descent. 2441 * To obtain a visual bounding box, which encloses all the text, 2442 * use the {@link TextLayout#getBounds() getBounds} method of 2443 * <code>TextLayout</code>. 2444 * <p>Note: The returned bounds is in baseline-relative coordinates 2445 * (see {@link java.awt.Font class notes}). 2446 * @param ci the specified <code>CharacterIterator</code> 2447 * @param beginIndex the initial offset in <code>ci</code> 2448 * @param limit the end offset in <code>ci</code> 2449 * @param frc the specified <code>FontRenderContext</code> 2450 * @return a <code>Rectangle2D</code> that is the bounding box of the 2451 * characters indexed in the specified <code>CharacterIterator</code> 2452 * in the specified <code>FontRenderContext</code>. 2453 * @see FontRenderContext 2454 * @see Font#createGlyphVector 2455 * @since 1.2 2456 * @throws IndexOutOfBoundsException if <code>beginIndex</code> is 2457 * less than the start index of <code>ci</code>, or 2458 * <code>limit</code> is greater than the end index of 2459 * <code>ci</code>, or <code>beginIndex</code> is greater 2460 * than <code>limit</code> 2461 */ 2462 public Rectangle2D getStringBounds(CharacterIterator ci, 2463 int beginIndex, int limit, 2464 FontRenderContext frc) { 2465 int start = ci.getBeginIndex(); 2466 int end = ci.getEndIndex(); 2467 2468 if (beginIndex < start) { 2469 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); 2470 } 2471 if (limit > end) { 2472 throw new IndexOutOfBoundsException("limit: " + limit); 2473 } 2474 if (beginIndex > limit) { 2475 throw new IndexOutOfBoundsException("range length: " + 2476 (limit - beginIndex)); 2477 } 2478 2479 char[] arr = new char[limit - beginIndex]; 2480 2481 ci.setIndex(beginIndex); 2482 for(int idx = 0; idx < arr.length; idx++) { 2483 arr[idx] = ci.current(); 2484 ci.next(); 2485 } 2486 2487 return getStringBounds(arr,0,arr.length,frc); 2488 } 2489 2490 /** 2491 * Returns the bounds for the character with the maximum 2492 * bounds as defined in the specified <code>FontRenderContext</code>. 2493 * <p>Note: The returned bounds is in baseline-relative coordinates 2494 * (see {@link java.awt.Font class notes}). 2495 * @param frc the specified <code>FontRenderContext</code> 2496 * @return a <code>Rectangle2D</code> that is the bounding box 2497 * for the character with the maximum bounds. 2498 */ 2499 public Rectangle2D getMaxCharBounds(FontRenderContext frc) { 2500 float [] metrics = new float[4]; 2501 2502 getFont2D().getFontMetrics(this, frc, metrics); 2503 2504 return new Rectangle2D.Float(0, -metrics[0], 2505 metrics[3], 2506 metrics[0] + metrics[1] + metrics[2]); 2507 } 2508 2509 /** 2510 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2511 * mapping characters to glyphs one-to-one based on the 2512 * Unicode cmap in this <code>Font</code>. This method does no other 2513 * processing besides the mapping of glyphs to characters. This 2514 * means that this method is not useful for some scripts, such 2515 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2516 * shaping, or ligature substitution. 2517 * @param frc the specified <code>FontRenderContext</code> 2518 * @param str the specified <code>String</code> 2519 * @return a new <code>GlyphVector</code> created with the 2520 * specified <code>String</code> and the specified 2521 * <code>FontRenderContext</code>. 2522 */ 2523 public GlyphVector createGlyphVector(FontRenderContext frc, String str) 2524 { 2525 return (GlyphVector)new StandardGlyphVector(this, str, frc); 2526 } 2527 2528 /** 2529 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2530 * mapping characters to glyphs one-to-one based on the 2531 * Unicode cmap in this <code>Font</code>. This method does no other 2532 * processing besides the mapping of glyphs to characters. This 2533 * means that this method is not useful for some scripts, such 2534 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2535 * shaping, or ligature substitution. 2536 * @param frc the specified <code>FontRenderContext</code> 2537 * @param chars the specified array of characters 2538 * @return a new <code>GlyphVector</code> created with the 2539 * specified array of characters and the specified 2540 * <code>FontRenderContext</code>. 2541 */ 2542 public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) 2543 { 2544 return (GlyphVector)new StandardGlyphVector(this, chars, frc); 2545 } 2546 2547 /** 2548 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2549 * mapping the specified characters to glyphs one-to-one based on the 2550 * Unicode cmap in this <code>Font</code>. This method does no other 2551 * processing besides the mapping of glyphs to characters. This 2552 * means that this method is not useful for some scripts, such 2553 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2554 * shaping, or ligature substitution. 2555 * @param frc the specified <code>FontRenderContext</code> 2556 * @param ci the specified <code>CharacterIterator</code> 2557 * @return a new <code>GlyphVector</code> created with the 2558 * specified <code>CharacterIterator</code> and the specified 2559 * <code>FontRenderContext</code>. 2560 */ 2561 public GlyphVector createGlyphVector( FontRenderContext frc, 2562 CharacterIterator ci) 2563 { 2564 return (GlyphVector)new StandardGlyphVector(this, ci, frc); 2565 } 2566 2567 /** 2568 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2569 * mapping characters to glyphs one-to-one based on the 2570 * Unicode cmap in this <code>Font</code>. This method does no other 2571 * processing besides the mapping of glyphs to characters. This 2572 * means that this method is not useful for some scripts, such 2573 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2574 * shaping, or ligature substitution. 2575 * @param frc the specified <code>FontRenderContext</code> 2576 * @param glyphCodes the specified integer array 2577 * @return a new <code>GlyphVector</code> created with the 2578 * specified integer array and the specified 2579 * <code>FontRenderContext</code>. 2580 */ 2581 public GlyphVector createGlyphVector( FontRenderContext frc, 2582 int [] glyphCodes) 2583 { 2584 return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc); 2585 } 2586 2587 /** 2588 * Returns a new <code>GlyphVector</code> object, performing full 2589 * layout of the text if possible. Full layout is required for 2590 * complex text, such as Arabic or Hindi. Support for different 2591 * scripts depends on the font and implementation. 2592 * <p> 2593 * Layout requires bidi analysis, as performed by 2594 * <code>Bidi</code>, and should only be performed on text that 2595 * has a uniform direction. The direction is indicated in the 2596 * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a 2597 * right-to-left (Arabic and Hebrew) run direction, or 2598 * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English) 2599 * run direction. 2600 * <p> 2601 * In addition, some operations, such as Arabic shaping, require 2602 * context, so that the characters at the start and limit can have 2603 * the proper shapes. Sometimes the data in the buffer outside 2604 * the provided range does not have valid data. The values 2605 * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be 2606 * added to the flags parameter to indicate that the text before 2607 * start, or after limit, respectively, should not be examined 2608 * for context. 2609 * <p> 2610 * All other values for the flags parameter are reserved. 2611 * 2612 * @param frc the specified <code>FontRenderContext</code> 2613 * @param text the text to layout 2614 * @param start the start of the text to use for the <code>GlyphVector</code> 2615 * @param limit the limit of the text to use for the <code>GlyphVector</code> 2616 * @param flags control flags as described above 2617 * @return a new <code>GlyphVector</code> representing the text between 2618 * start and limit, with glyphs chosen and positioned so as to best represent 2619 * the text 2620 * @throws ArrayIndexOutOfBoundsException if start or limit is 2621 * out of bounds 2622 * @see java.text.Bidi 2623 * @see #LAYOUT_LEFT_TO_RIGHT 2624 * @see #LAYOUT_RIGHT_TO_LEFT 2625 * @see #LAYOUT_NO_START_CONTEXT 2626 * @see #LAYOUT_NO_LIMIT_CONTEXT 2627 * @since 1.4 2628 */ 2629 public GlyphVector layoutGlyphVector(FontRenderContext frc, 2630 char[] text, 2631 int start, 2632 int limit, 2633 int flags) { 2634 2635 GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines 2636 StandardGlyphVector gv = gl.layout(this, frc, text, 2637 start, limit-start, flags, null); 2638 GlyphLayout.done(gl); 2639 return gv; 2640 } 2641 2642 /** 2643 * A flag to layoutGlyphVector indicating that text is left-to-right as 2644 * determined by Bidi analysis. 2645 */ 2646 public static final int LAYOUT_LEFT_TO_RIGHT = 0; 2647 2648 /** 2649 * A flag to layoutGlyphVector indicating that text is right-to-left as 2650 * determined by Bidi analysis. 2651 */ 2652 public static final int LAYOUT_RIGHT_TO_LEFT = 1; 2653 2654 /** 2655 * A flag to layoutGlyphVector indicating that text in the char array 2656 * before the indicated start should not be examined. 2657 */ 2658 public static final int LAYOUT_NO_START_CONTEXT = 2; 2659 2660 /** 2661 * A flag to layoutGlyphVector indicating that text in the char array 2662 * after the indicated limit should not be examined. 2663 */ 2664 public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; 2665 2666 2667 private static void applyTransform(AffineTransform trans, AttributeValues values) { 2668 if (trans == null) { 2669 throw new IllegalArgumentException("transform must not be null"); 2670 } 2671 values.setTransform(trans); 2672 } 2673 2674 private static void applyStyle(int style, AttributeValues values) { 2675 // WEIGHT_BOLD, WEIGHT_REGULAR 2676 values.setWeight((style & BOLD) != 0 ? 2f : 1f); 2677 // POSTURE_OBLIQUE, POSTURE_REGULAR 2678 values.setPosture((style & ITALIC) != 0 ? .2f : 0f); 2679 } 2680 2681 /* 2682 * Initialize JNI field and method IDs 2683 */ 2684 private static native void initIDs(); 2685 }