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