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