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