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 true if any part of the specified text is from a 770 * complex script for which the implementation will need to invoke 771 * layout processing in order to render correctly when using 772 * {@link Graphics#drawString(String,int,int) drawString(String,int,int)} 773 * and other text rendering methods. Measurement of the text 774 * may similarly need the same extra processing. 775 * The {@code start} and {@code end} indices are provided so that 776 * the application can request only a subset of the text be considered. 777 * The last char index examined is at {@code "end-1"}, 778 * i.e a request to examine the entire array would be 779 * <pre> 780 * {@code Font.textRequiresLayout(chars, 0, chars.length);} 781 * </pre> 782 * An application may find this information helpful in 783 * performance sensitive code. 784 * <p> 785 * Note that even if this method returns {@code false}, layout processing 786 * may still be invoked when used with any {@code Font} 787 * for which {@link #hasLayoutAttributes()} returns {@code true}, 788 * so that method will need to be consulted for the specific font, 789 * in order to obtain an answer which accounts for such font attributes. 790 * 791 * @param chars the text. 792 * @param start the index of the first char to examine. 793 * @param end the ending index, exclusive. 794 * @return {@code true} if the specified text will need special layout. 795 * @throws NullPointerException if {@code chars} is null. 796 * @throws ArrayIndexOutOfBoundsException if {@code start} is negative or 797 * {@code end} is greater than the length of the {@code chars} array. 798 * @since 9 799 */ 800 public static boolean textRequiresLayout(char[] chars, 801 int start, int end) { 802 if (chars == null) { 803 throw new NullPointerException("null char array"); 804 } 805 if (start < 0 || end > chars.length) { 806 throw new ArrayIndexOutOfBoundsException("start < 0 or end > len"); 807 } 808 return FontUtilities.isComplexScript(chars, start, end); 809 } 810 811 /** 812 * Returns a {@code Font} appropriate to the attributes. 813 * If {@code attributes} contains a {@code FONT} attribute 814 * with a valid {@code Font} as its value, it will be 815 * merged with any remaining attributes. See 816 * {@link java.awt.font.TextAttribute#FONT} for more 817 * information. 818 * 819 * @param attributes the attributes to assign to the new 820 * {@code Font} 821 * @return a new {@code Font} created with the specified 822 * attributes 823 * @throws NullPointerException if {@code attributes} is null. 824 * @since 1.2 825 * @see java.awt.font.TextAttribute 826 */ 827 public static Font getFont(Map<? extends Attribute, ?> attributes) { 828 // optimize for two cases: 829 // 1) FONT attribute, and nothing else 830 // 2) attributes, but no FONT 831 832 // avoid turning the attributemap into a regular map for no reason 833 if (attributes instanceof AttributeMap && 834 ((AttributeMap)attributes).getValues() != null) { 835 AttributeValues values = ((AttributeMap)attributes).getValues(); 836 if (values.isNonDefault(EFONT)) { 837 Font font = values.getFont(); 838 if (!values.anyDefined(SECONDARY_MASK)) { 839 return font; 840 } 841 // merge 842 values = font.getAttributeValues().clone(); 843 values.merge(attributes, SECONDARY_MASK); 844 return new Font(values, font.name, font.style, 845 font.createdFont, font.font2DHandle); 846 } 847 return new Font(attributes); 848 } 849 850 Font font = (Font)attributes.get(TextAttribute.FONT); 851 if (font != null) { 852 if (attributes.size() > 1) { // oh well, check for anything else 853 AttributeValues values = font.getAttributeValues().clone(); 854 values.merge(attributes, SECONDARY_MASK); 855 return new Font(values, font.name, font.style, 856 font.createdFont, font.font2DHandle); 857 } 858 859 return font; 860 } 861 862 return new Font(attributes); 863 } 864 865 /** 866 * Used with the byte count tracker for fonts created from streams. 867 * If a thread can create temp files anyway, no point in counting 868 * font bytes. 869 */ 870 private static boolean hasTempPermission() { 871 872 if (System.getSecurityManager() == null) { 873 return true; 874 } 875 File f = null; 876 boolean hasPerm = false; 877 try { 878 f = Files.createTempFile("+~JT", ".tmp").toFile(); 879 f.delete(); 880 f = null; 881 hasPerm = true; 882 } catch (Throwable t) { 883 /* inc. any kind of SecurityException */ 884 } 885 return hasPerm; 886 } 887 888 889 /** 890 * Returns a new array of {@code Font} decoded from the specified stream. 891 * The returned {@code Font[]} will have at least one element. 892 * <p> 893 * The explicit purpose of this variation on the 894 * {@code createFont(int, InputStream)} method is to support font 895 * sources which represent a TrueType/OpenType font collection and 896 * be able to return all individual fonts in that collection. 897 * Consequently this method will throw {@code FontFormatException} 898 * if the data source does not contain at least one TrueType/OpenType 899 * font. The same exception will also be thrown if any of the fonts in 900 * the collection does not contain the required font tables. 901 * <p> 902 * The condition "at least one", allows for the stream to represent 903 * a single OpenType/TrueType font. That is, it does not have to be 904 * a collection. 905 * Each {@code Font} element of the returned array is 906 * created with a point size of 1 and style {@link #PLAIN PLAIN}. 907 * This base font can then be used with the {@code deriveFont} 908 * methods in this class to derive new {@code Font} objects with 909 * varying sizes, styles, transforms and font features. 910 * <p>This method does not close the {@link InputStream}. 911 * <p> 912 * To make each {@code Font} available to Font constructors it 913 * must be registered in the {@code GraphicsEnvironment} by calling 914 * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. 915 * @param fontStream an {@code InputStream} object representing the 916 * input data for the font or font collection. 917 * @return a new {@code Font[]}. 918 * @throws FontFormatException if the {@code fontStream} data does 919 * not contain the required font tables for any of the elements of 920 * the collection, or if it contains no fonts at all. 921 * @throws IOException if the {@code fontStream} cannot be completely read. 922 * @see GraphicsEnvironment#registerFont(Font) 923 * @since 9 924 */ 925 public static Font[] createFonts(InputStream fontStream) 926 throws FontFormatException, IOException { 927 928 final int fontFormat = Font.TRUETYPE_FONT; 929 if (hasTempPermission()) { 930 return createFont0(fontFormat, fontStream, true, null); 931 } 932 933 // Otherwise, be extra conscious of pending temp file creation and 934 // resourcefully handle the temp file resources, among other things. 935 CreatedFontTracker tracker = CreatedFontTracker.getTracker(); 936 boolean acquired = false; 937 try { 938 acquired = tracker.acquirePermit(); 939 if (!acquired) { 940 throw new IOException("Timed out waiting for resources."); 941 } 942 return createFont0(fontFormat, fontStream, true, tracker); 943 } catch (InterruptedException e) { 944 throw new IOException("Problem reading font data."); 945 } finally { 946 if (acquired) { 947 tracker.releasePermit(); 948 } 949 } 950 } 951 952 /* used to implement Font.createFont */ 953 private Font(Font2D font2D) { 954 955 this.createdFont = true; 956 this.font2DHandle = font2D.handle; 957 this.name = font2D.getFontName(Locale.getDefault()); 958 this.style = Font.PLAIN; 959 this.size = 1; 960 this.pointSize = 1f; 961 } 962 963 /** 964 * Returns a new array of {@code Font} decoded from the specified file. 965 * The returned {@code Font[]} will have at least one element. 966 * <p> 967 * The explicit purpose of this variation on the 968 * {@code createFont(int, File)} method is to support font 969 * sources which represent a TrueType/OpenType font collection and 970 * be able to return all individual fonts in that collection. 971 * Consequently this method will throw {@code FontFormatException} 972 * if the data source does not contain at least one TrueType/OpenType 973 * font. The same exception will also be thrown if any of the fonts in 974 * the collection does not contain the required font tables. 975 * <p> 976 * The condition "at least one", allows for the stream to represent 977 * a single OpenType/TrueType font. That is, it does not have to be 978 * a collection. 979 * Each {@code Font} element of the returned array is 980 * created with a point size of 1 and style {@link #PLAIN PLAIN}. 981 * This base font can then be used with the {@code deriveFont} 982 * methods in this class to derive new {@code Font} objects with 983 * varying sizes, styles, transforms and font features. 984 * <p> 985 * To make each {@code Font} available to Font constructors it 986 * must be registered in the {@code GraphicsEnvironment} by calling 987 * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. 988 * @param fontFile a {@code File} object containing the 989 * input data for the font or font collection. 990 * @return a new {@code Font[]}. 991 * @throws FontFormatException if the {@code File} does 992 * not contain the required font tables for any of the elements of 993 * the collection, or if it contains no fonts at all. 994 * @throws IOException if the {@code fontFile} cannot be read. 995 * @see GraphicsEnvironment#registerFont(Font) 996 * @since 9 997 */ 998 public static Font[] createFonts(File fontFile) 999 throws FontFormatException, IOException 1000 { 1001 int fontFormat = Font.TRUETYPE_FONT; 1002 fontFile = checkFontFile(fontFormat, fontFile); 1003 FontManager fm = FontManagerFactory.getInstance(); 1004 Font2D[] font2DArr = 1005 fm.createFont2D(fontFile, fontFormat, true, false, null); 1006 int num = font2DArr.length; 1007 Font[] fonts = new Font[num]; 1008 for (int i = 0; i < num; i++) { 1009 fonts[i] = new Font(font2DArr[i]); 1010 } 1011 return fonts; 1012 } 1013 1014 /** 1015 * Returns a new {@code Font} using the specified font type 1016 * and input data. The new {@code Font} is 1017 * created with a point size of 1 and style {@link #PLAIN PLAIN}. 1018 * This base font can then be used with the {@code deriveFont} 1019 * methods in this class to derive new {@code Font} objects with 1020 * varying sizes, styles, transforms and font features. This 1021 * method does not close the {@link InputStream}. 1022 * <p> 1023 * To make the {@code Font} available to Font constructors the 1024 * returned {@code Font} must be registered in the 1025 * {@code GraphicsEnvironment} by calling 1026 * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. 1027 * @param fontFormat the type of the {@code Font}, which is 1028 * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified. 1029 * or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified. 1030 * @param fontStream an {@code InputStream} object representing the 1031 * input data for the font. 1032 * @return a new {@code Font} created with the specified font type. 1033 * @throws IllegalArgumentException if {@code fontFormat} is not 1034 * {@code TRUETYPE_FONT} or {@code TYPE1_FONT}. 1035 * @throws FontFormatException if the {@code fontStream} data does 1036 * not contain the required font tables for the specified format. 1037 * @throws IOException if the {@code fontStream} 1038 * cannot be completely read. 1039 * @see GraphicsEnvironment#registerFont(Font) 1040 * @since 1.3 1041 */ 1042 public static Font createFont(int fontFormat, InputStream fontStream) 1043 throws java.awt.FontFormatException, java.io.IOException { 1044 1045 if (hasTempPermission()) { 1046 return createFont0(fontFormat, fontStream, false, null)[0]; 1047 } 1048 1049 // Otherwise, be extra conscious of pending temp file creation and 1050 // resourcefully handle the temp file resources, among other things. 1051 CreatedFontTracker tracker = CreatedFontTracker.getTracker(); 1052 boolean acquired = false; 1053 try { 1054 acquired = tracker.acquirePermit(); 1055 if (!acquired) { 1056 throw new IOException("Timed out waiting for resources."); 1057 } 1058 return createFont0(fontFormat, fontStream, false, tracker)[0]; 1059 } catch (InterruptedException e) { 1060 throw new IOException("Problem reading font data."); 1061 } finally { 1062 if (acquired) { 1063 tracker.releasePermit(); 1064 } 1065 } 1066 } 1067 1068 private static Font[] createFont0(int fontFormat, InputStream fontStream, 1069 boolean allFonts, 1070 CreatedFontTracker tracker) 1071 throws java.awt.FontFormatException, java.io.IOException { 1072 1073 if (fontFormat != Font.TRUETYPE_FONT && 1074 fontFormat != Font.TYPE1_FONT) { 1075 throw new IllegalArgumentException ("font format not recognized"); 1076 } 1077 boolean copiedFontData = false; 1078 try { 1079 final File tFile = AccessController.doPrivileged( 1080 new PrivilegedExceptionAction<File>() { 1081 public File run() throws IOException { 1082 return Files.createTempFile("+~JF", ".tmp").toFile(); 1083 } 1084 } 1085 ); 1086 if (tracker != null) { 1087 tracker.add(tFile); 1088 } 1089 1090 int totalSize = 0; 1091 try { 1092 final OutputStream outStream = 1093 AccessController.doPrivileged( 1094 new PrivilegedExceptionAction<OutputStream>() { 1095 public OutputStream run() throws IOException { 1096 return new FileOutputStream(tFile); 1097 } 1098 } 1099 ); 1100 if (tracker != null) { 1101 tracker.set(tFile, outStream); 1102 } 1103 try { 1104 byte[] buf = new byte[8192]; 1105 for (;;) { 1106 int bytesRead = fontStream.read(buf); 1107 if (bytesRead < 0) { 1108 break; 1109 } 1110 if (tracker != null) { 1111 if (totalSize+bytesRead > CreatedFontTracker.MAX_FILE_SIZE) { 1112 throw new IOException("File too big."); 1113 } 1114 if (totalSize+tracker.getNumBytes() > 1115 CreatedFontTracker.MAX_TOTAL_BYTES) 1116 { 1117 throw new IOException("Total files too big."); 1118 } 1119 totalSize += bytesRead; 1120 tracker.addBytes(bytesRead); 1121 } 1122 outStream.write(buf, 0, bytesRead); 1123 } 1124 /* don't close the input stream */ 1125 } finally { 1126 outStream.close(); 1127 } 1128 /* After all references to a Font2D are dropped, the file 1129 * will be removed. To support long-lived AppContexts, 1130 * we need to then decrement the byte count by the size 1131 * of the file. 1132 * If the data isn't a valid font, the implementation will 1133 * delete the tmp file and decrement the byte count 1134 * in the tracker object before returning from the 1135 * constructor, so we can set 'copiedFontData' to true here 1136 * without waiting for the results of that constructor. 1137 */ 1138 copiedFontData = true; 1139 FontManager fm = FontManagerFactory.getInstance(); 1140 Font2D[] font2DArr = 1141 fm.createFont2D(tFile, fontFormat, allFonts, true, tracker); 1142 int num = font2DArr.length; 1143 Font[] fonts = new Font[num]; 1144 for (int i = 0; i < num; i++) { 1145 fonts[i] = new Font(font2DArr[i]); 1146 } 1147 return fonts; 1148 } finally { 1149 if (tracker != null) { 1150 tracker.remove(tFile); 1151 } 1152 if (!copiedFontData) { 1153 if (tracker != null) { 1154 tracker.subBytes(totalSize); 1155 } 1156 AccessController.doPrivileged( 1157 new PrivilegedExceptionAction<Void>() { 1158 public Void run() { 1159 tFile.delete(); 1160 return null; 1161 } 1162 } 1163 ); 1164 } 1165 } 1166 } catch (Throwable t) { 1167 if (t instanceof FontFormatException) { 1168 throw (FontFormatException)t; 1169 } 1170 if (t instanceof IOException) { 1171 throw (IOException)t; 1172 } 1173 Throwable cause = t.getCause(); 1174 if (cause instanceof FontFormatException) { 1175 throw (FontFormatException)cause; 1176 } 1177 throw new IOException("Problem reading font data."); 1178 } 1179 } 1180 1181 /** 1182 * Returns a new {@code Font} using the specified font type 1183 * and the specified font file. The new {@code Font} is 1184 * created with a point size of 1 and style {@link #PLAIN PLAIN}. 1185 * This base font can then be used with the {@code deriveFont} 1186 * methods in this class to derive new {@code Font} objects with 1187 * varying sizes, styles, transforms and font features. 1188 * @param fontFormat the type of the {@code Font}, which is 1189 * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is 1190 * specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is 1191 * specified. 1192 * So long as the returned font, or its derived fonts are referenced 1193 * the implementation may continue to access {@code fontFile} 1194 * to retrieve font data. Thus the results are undefined if the file 1195 * is changed, or becomes inaccessible. 1196 * <p> 1197 * To make the {@code Font} available to Font constructors the 1198 * returned {@code Font} must be registered in the 1199 * {@code GraphicsEnvironment} by calling 1200 * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}. 1201 * @param fontFile a {@code File} object representing the 1202 * input data for the font. 1203 * @return a new {@code Font} created with the specified font type. 1204 * @throws IllegalArgumentException if {@code fontFormat} is not 1205 * {@code TRUETYPE_FONT} or {@code TYPE1_FONT}. 1206 * @throws NullPointerException if {@code fontFile} is null. 1207 * @throws IOException if the {@code fontFile} cannot be read. 1208 * @throws FontFormatException if {@code fontFile} does 1209 * not contain the required font tables for the specified format. 1210 * @throws SecurityException if the executing code does not have 1211 * permission to read from the file. 1212 * @see GraphicsEnvironment#registerFont(Font) 1213 * @since 1.5 1214 */ 1215 public static Font createFont(int fontFormat, File fontFile) 1216 throws java.awt.FontFormatException, java.io.IOException { 1217 1218 fontFile = checkFontFile(fontFormat, fontFile); 1219 return new Font(fontFile, fontFormat, false, null); 1220 } 1221 1222 private static File checkFontFile(int fontFormat, File fontFile) 1223 throws FontFormatException, IOException { 1224 1225 fontFile = new File(fontFile.getPath()); 1226 1227 if (fontFormat != Font.TRUETYPE_FONT && 1228 fontFormat != Font.TYPE1_FONT) { 1229 throw new IllegalArgumentException ("font format not recognized"); 1230 } 1231 SecurityManager sm = System.getSecurityManager(); 1232 if (sm != null) { 1233 FilePermission filePermission = 1234 new FilePermission(fontFile.getPath(), "read"); 1235 sm.checkPermission(filePermission); 1236 } 1237 if (!fontFile.canRead()) { 1238 throw new IOException("Can't read " + fontFile); 1239 } 1240 return fontFile; 1241 } 1242 1243 /** 1244 * Returns a copy of the transform associated with this 1245 * {@code Font}. This transform is not necessarily the one 1246 * used to construct the font. If the font has algorithmic 1247 * superscripting or width adjustment, this will be incorporated 1248 * into the returned {@code AffineTransform}. 1249 * <p> 1250 * Typically, fonts will not be transformed. Clients generally 1251 * should call {@link #isTransformed} first, and only call this 1252 * method if {@code isTransformed} returns true. 1253 * 1254 * @return an {@link AffineTransform} object representing the 1255 * transform attribute of this {@code Font} object. 1256 */ 1257 public AffineTransform getTransform() { 1258 /* The most common case is the identity transform. Most callers 1259 * should call isTransformed() first, to decide if they need to 1260 * get the transform, but some may not. Here we check to see 1261 * if we have a nonidentity transform, and only do the work to 1262 * fetch and/or compute it if so, otherwise we return a new 1263 * identity transform. 1264 * 1265 * Note that the transform is _not_ necessarily the same as 1266 * the transform passed in as an Attribute in a Map, as the 1267 * transform returned will also reflect the effects of WIDTH and 1268 * SUPERSCRIPT attributes. Clients who want the actual transform 1269 * need to call getRequestedAttributes. 1270 */ 1271 if (nonIdentityTx) { 1272 AttributeValues values = getAttributeValues(); 1273 1274 AffineTransform at = values.isNonDefault(ETRANSFORM) 1275 ? new AffineTransform(values.getTransform()) 1276 : new AffineTransform(); 1277 1278 if (values.getSuperscript() != 0) { 1279 // can't get ascent and descent here, recursive call to this fn, 1280 // so use pointsize 1281 // let users combine super- and sub-scripting 1282 1283 int superscript = values.getSuperscript(); 1284 1285 double trans = 0; 1286 int n = 0; 1287 boolean up = superscript > 0; 1288 int sign = up ? -1 : 1; 1289 int ss = up ? superscript : -superscript; 1290 1291 while ((ss & 7) > n) { 1292 int newn = ss & 7; 1293 trans += sign * (ssinfo[newn] - ssinfo[n]); 1294 ss >>= 3; 1295 sign = -sign; 1296 n = newn; 1297 } 1298 trans *= pointSize; 1299 double scale = Math.pow(2./3., n); 1300 1301 at.preConcatenate(AffineTransform.getTranslateInstance(0, trans)); 1302 at.scale(scale, scale); 1303 1304 // note on placement and italics 1305 // We preconcatenate the transform because we don't want to translate along 1306 // the italic angle, but purely perpendicular to the baseline. While this 1307 // looks ok for superscripts, it can lead subscripts to stack on each other 1308 // and bring the following text too close. The way we deal with potential 1309 // collisions that can occur in the case of italics is by adjusting the 1310 // horizontal spacing of the adjacent glyphvectors. Examine the italic 1311 // angle of both vectors, if one is non-zero, compute the minimum ascent 1312 // and descent, and then the x position at each for each vector along its 1313 // italic angle starting from its (offset) baseline. Compute the difference 1314 // between the x positions and use the maximum difference to adjust the 1315 // position of the right gv. 1316 } 1317 1318 if (values.isNonDefault(EWIDTH)) { 1319 at.scale(values.getWidth(), 1f); 1320 } 1321 1322 return at; 1323 } 1324 1325 return new AffineTransform(); 1326 } 1327 1328 // x = r^0 + r^1 + r^2... r^n 1329 // rx = r^1 + r^2 + r^3... r^(n+1) 1330 // x - rx = r^0 - r^(n+1) 1331 // x (1 - r) = r^0 - r^(n+1) 1332 // x = (r^0 - r^(n+1)) / (1 - r) 1333 // x = (1 - r^(n+1)) / (1 - r) 1334 1335 // scale ratio is 2/3 1336 // trans = 1/2 of ascent * x 1337 // assume ascent is 3/4 of point size 1338 1339 private static final float[] ssinfo = { 1340 0.0f, 1341 0.375f, 1342 0.625f, 1343 0.7916667f, 1344 0.9027778f, 1345 0.9768519f, 1346 1.0262346f, 1347 1.0591564f, 1348 }; 1349 1350 /** 1351 * Returns the family name of this {@code Font}. 1352 * 1353 * <p>The family name of a font is font specific. Two fonts such as 1354 * Helvetica Italic and Helvetica Bold have the same family name, 1355 * <i>Helvetica</i>, whereas their font face names are 1356 * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of 1357 * available family names may be obtained by using the 1358 * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. 1359 * 1360 * <p>Use {@code getName} to get the logical name of the font. 1361 * Use {@code getFontName} to get the font face name of the font. 1362 * @return a {@code String} that is the family name of this 1363 * {@code Font}. 1364 * 1365 * @see #getName 1366 * @see #getFontName 1367 * @since 1.1 1368 */ 1369 public String getFamily() { 1370 return getFamily_NoClientCode(); 1371 } 1372 // NOTE: This method is called by privileged threads. 1373 // We implement this functionality in a package-private 1374 // method to insure that it cannot be overridden by client 1375 // subclasses. 1376 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 1377 final String getFamily_NoClientCode() { 1378 return getFamily(Locale.getDefault()); 1379 } 1380 1381 /** 1382 * Returns the family name of this {@code Font}, localized for 1383 * the specified locale. 1384 * 1385 * <p>The family name of a font is font specific. Two fonts such as 1386 * Helvetica Italic and Helvetica Bold have the same family name, 1387 * <i>Helvetica</i>, whereas their font face names are 1388 * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of 1389 * available family names may be obtained by using the 1390 * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. 1391 * 1392 * <p>Use {@code getFontName} to get the font face name of the font. 1393 * @param l locale for which to get the family name 1394 * @return a {@code String} representing the family name of the 1395 * font, localized for the specified locale. 1396 * @see #getFontName 1397 * @see java.util.Locale 1398 * @since 1.2 1399 */ 1400 public String getFamily(Locale l) { 1401 if (l == null) { 1402 throw new NullPointerException("null locale doesn't mean default"); 1403 } 1404 return getFont2D().getFamilyName(l); 1405 } 1406 1407 /** 1408 * Returns the postscript name of this {@code Font}. 1409 * Use {@code getFamily} to get the family name of the font. 1410 * Use {@code getFontName} to get the font face name of the font. 1411 * @return a {@code String} representing the postscript name of 1412 * this {@code Font}. 1413 * @since 1.2 1414 */ 1415 public String getPSName() { 1416 return getFont2D().getPostscriptName(); 1417 } 1418 1419 /** 1420 * Returns the logical name of this {@code Font}. 1421 * Use {@code getFamily} to get the family name of the font. 1422 * Use {@code getFontName} to get the font face name of the font. 1423 * @return a {@code String} representing the logical name of 1424 * this {@code Font}. 1425 * @see #getFamily 1426 * @see #getFontName 1427 * @since 1.0 1428 */ 1429 public String getName() { 1430 return name; 1431 } 1432 1433 /** 1434 * Returns the font face name of this {@code Font}. For example, 1435 * Helvetica Bold could be returned as a font face name. 1436 * Use {@code getFamily} to get the family name of the font. 1437 * Use {@code getName} to get the logical name of the font. 1438 * @return a {@code String} representing the font face name of 1439 * this {@code Font}. 1440 * @see #getFamily 1441 * @see #getName 1442 * @since 1.2 1443 */ 1444 public String getFontName() { 1445 return getFontName(Locale.getDefault()); 1446 } 1447 1448 /** 1449 * Returns the font face name of the {@code Font}, localized 1450 * for the specified locale. For example, Helvetica Fett could be 1451 * returned as the font face name. 1452 * Use {@code getFamily} to get the family name of the font. 1453 * @param l a locale for which to get the font face name 1454 * @return a {@code String} representing the font face name, 1455 * localized for the specified locale. 1456 * @see #getFamily 1457 * @see java.util.Locale 1458 */ 1459 public String getFontName(Locale l) { 1460 if (l == null) { 1461 throw new NullPointerException("null locale doesn't mean default"); 1462 } 1463 return getFont2D().getFontName(l); 1464 } 1465 1466 /** 1467 * Returns the style of this {@code Font}. The style can be 1468 * PLAIN, BOLD, ITALIC, or BOLD+ITALIC. 1469 * @return the style of this {@code Font} 1470 * @see #isPlain 1471 * @see #isBold 1472 * @see #isItalic 1473 * @since 1.0 1474 */ 1475 public int getStyle() { 1476 return style; 1477 } 1478 1479 /** 1480 * Returns the point size of this {@code Font}, rounded to 1481 * an integer. 1482 * Most users are familiar with the idea of using <i>point size</i> to 1483 * specify the size of glyphs in a font. This point size defines a 1484 * measurement between the baseline of one line to the baseline of the 1485 * following line in a single spaced text document. The point size is 1486 * based on <i>typographic points</i>, approximately 1/72 of an inch. 1487 * <p> 1488 * The Java(tm)2D API adopts the convention that one point is 1489 * equivalent to one unit in user coordinates. When using a 1490 * normalized transform for converting user space coordinates to 1491 * device space coordinates 72 user 1492 * space units equal 1 inch in device space. In this case one point 1493 * is 1/72 of an inch. 1494 * @return the point size of this {@code Font} in 1/72 of an 1495 * inch units. 1496 * @see #getSize2D 1497 * @see GraphicsConfiguration#getDefaultTransform 1498 * @see GraphicsConfiguration#getNormalizingTransform 1499 * @since 1.0 1500 */ 1501 public int getSize() { 1502 return size; 1503 } 1504 1505 /** 1506 * Returns the point size of this {@code Font} in 1507 * {@code float} value. 1508 * @return the point size of this {@code Font} as a 1509 * {@code float} value. 1510 * @see #getSize 1511 * @since 1.2 1512 */ 1513 public float getSize2D() { 1514 return pointSize; 1515 } 1516 1517 /** 1518 * Indicates whether or not this {@code Font} object's style is 1519 * PLAIN. 1520 * @return {@code true} if this {@code Font} has a 1521 * PLAIN style; 1522 * {@code false} otherwise. 1523 * @see java.awt.Font#getStyle 1524 * @since 1.0 1525 */ 1526 public boolean isPlain() { 1527 return style == 0; 1528 } 1529 1530 /** 1531 * Indicates whether or not this {@code Font} object's style is 1532 * BOLD. 1533 * @return {@code true} if this {@code Font} object's 1534 * style is BOLD; 1535 * {@code false} otherwise. 1536 * @see java.awt.Font#getStyle 1537 * @since 1.0 1538 */ 1539 public boolean isBold() { 1540 return (style & BOLD) != 0; 1541 } 1542 1543 /** 1544 * Indicates whether or not this {@code Font} object's style is 1545 * ITALIC. 1546 * @return {@code true} if this {@code Font} object's 1547 * style is ITALIC; 1548 * {@code false} otherwise. 1549 * @see java.awt.Font#getStyle 1550 * @since 1.0 1551 */ 1552 public boolean isItalic() { 1553 return (style & ITALIC) != 0; 1554 } 1555 1556 /** 1557 * Indicates whether or not this {@code Font} object has a 1558 * transform that affects its size in addition to the Size 1559 * attribute. 1560 * @return {@code true} if this {@code Font} object 1561 * has a non-identity AffineTransform attribute. 1562 * {@code false} otherwise. 1563 * @see java.awt.Font#getTransform 1564 * @since 1.4 1565 */ 1566 public boolean isTransformed() { 1567 return nonIdentityTx; 1568 } 1569 1570 /** 1571 * Return true if this Font contains attributes that require extra 1572 * layout processing. 1573 * @return true if the font has layout attributes 1574 * @since 1.6 1575 */ 1576 public boolean hasLayoutAttributes() { 1577 return hasLayoutAttributes; 1578 } 1579 1580 /** 1581 * Returns a {@code Font} object from the system properties list. 1582 * {@code nm} is treated as the name of a system property to be 1583 * obtained. The {@code String} value of this property is then 1584 * interpreted as a {@code Font} object according to the 1585 * specification of {@code Font.decode(String)} 1586 * If the specified property is not found, or the executing code does 1587 * not have permission to read the property, null is returned instead. 1588 * 1589 * @param nm the property name 1590 * @return a {@code Font} object that the property name 1591 * describes, or null if no such property exists. 1592 * @throws NullPointerException if nm is null. 1593 * @since 1.2 1594 * @see #decode(String) 1595 */ 1596 public static Font getFont(String nm) { 1597 return getFont(nm, null); 1598 } 1599 1600 /** 1601 * Returns the {@code Font} that the {@code str} 1602 * argument describes. 1603 * To ensure that this method returns the desired Font, 1604 * format the {@code str} parameter in 1605 * one of these ways 1606 * 1607 * <ul> 1608 * <li><em>fontname-style-pointsize</em> 1609 * <li><em>fontname-pointsize</em> 1610 * <li><em>fontname-style</em> 1611 * <li><em>fontname</em> 1612 * <li><em>fontname style pointsize</em> 1613 * <li><em>fontname pointsize</em> 1614 * <li><em>fontname style</em> 1615 * <li><em>fontname</em> 1616 * </ul> 1617 * in which <i>style</i> is one of the four 1618 * case-insensitive strings: 1619 * {@code "PLAIN"}, {@code "BOLD"}, {@code "BOLDITALIC"}, or 1620 * {@code "ITALIC"}, and pointsize is a positive decimal integer 1621 * representation of the point size. 1622 * For example, if you want a font that is Arial, bold, with 1623 * a point size of 18, you would call this method with: 1624 * "Arial-BOLD-18". 1625 * This is equivalent to calling the Font constructor : 1626 * {@code new Font("Arial", Font.BOLD, 18);} 1627 * and the values are interpreted as specified by that constructor. 1628 * <p> 1629 * A valid trailing decimal field is always interpreted as the pointsize. 1630 * Therefore a fontname containing a trailing decimal value should not 1631 * be used in the fontname only form. 1632 * <p> 1633 * If a style name field is not one of the valid style strings, it is 1634 * interpreted as part of the font name, and the default style is used. 1635 * <p> 1636 * Only one of ' ' or '-' may be used to separate fields in the input. 1637 * The identified separator is the one closest to the end of the string 1638 * which separates a valid pointsize, or a valid style name from 1639 * the rest of the string. 1640 * Null (empty) pointsize and style fields are treated 1641 * as valid fields with the default value for that field. 1642 *<p> 1643 * Some font names may include the separator characters ' ' or '-'. 1644 * If {@code str} is not formed with 3 components, e.g. such that 1645 * {@code style} or {@code pointsize} fields are not present in 1646 * {@code str}, and {@code fontname} also contains a 1647 * character determined to be the separator character 1648 * then these characters where they appear as intended to be part of 1649 * {@code fontname} may instead be interpreted as separators 1650 * so the font name may not be properly recognised. 1651 * 1652 * <p> 1653 * The default size is 12 and the default style is PLAIN. 1654 * If {@code str} does not specify a valid size, the returned 1655 * {@code Font} has a size of 12. If {@code str} does not 1656 * specify a valid style, the returned Font has a style of PLAIN. 1657 * If you do not specify a valid font name in 1658 * the {@code str} argument, this method will return 1659 * a font with the family name "Dialog". 1660 * To determine what font family names are available on 1661 * your system, use the 1662 * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method. 1663 * If {@code str} is {@code null}, a new {@code Font} 1664 * is returned with the family name "Dialog", a size of 12 and a 1665 * PLAIN style. 1666 * @param str the name of the font, or {@code null} 1667 * @return the {@code Font} object that {@code str} 1668 * describes, or a new default {@code Font} if 1669 * {@code str} is {@code null}. 1670 * @see #getFamily 1671 * @since 1.1 1672 */ 1673 public static Font decode(String str) { 1674 String fontName = str; 1675 String styleName = ""; 1676 int fontSize = 12; 1677 int fontStyle = Font.PLAIN; 1678 1679 if (str == null) { 1680 return new Font(DIALOG, fontStyle, fontSize); 1681 } 1682 1683 int lastHyphen = str.lastIndexOf('-'); 1684 int lastSpace = str.lastIndexOf(' '); 1685 char sepChar = (lastHyphen > lastSpace) ? '-' : ' '; 1686 int sizeIndex = str.lastIndexOf(sepChar); 1687 int styleIndex = str.lastIndexOf(sepChar, sizeIndex-1); 1688 int strlen = str.length(); 1689 1690 if (sizeIndex > 0 && sizeIndex+1 < strlen) { 1691 try { 1692 fontSize = 1693 Integer.valueOf(str.substring(sizeIndex+1)).intValue(); 1694 if (fontSize <= 0) { 1695 fontSize = 12; 1696 } 1697 } catch (NumberFormatException e) { 1698 /* It wasn't a valid size, if we didn't also find the 1699 * start of the style string perhaps this is the style */ 1700 styleIndex = sizeIndex; 1701 sizeIndex = strlen; 1702 if (str.charAt(sizeIndex-1) == sepChar) { 1703 sizeIndex--; 1704 } 1705 } 1706 } 1707 1708 if (styleIndex >= 0 && styleIndex+1 < strlen) { 1709 styleName = str.substring(styleIndex+1, sizeIndex); 1710 styleName = styleName.toLowerCase(Locale.ENGLISH); 1711 if (styleName.equals("bolditalic")) { 1712 fontStyle = Font.BOLD | Font.ITALIC; 1713 } else if (styleName.equals("italic")) { 1714 fontStyle = Font.ITALIC; 1715 } else if (styleName.equals("bold")) { 1716 fontStyle = Font.BOLD; 1717 } else if (styleName.equals("plain")) { 1718 fontStyle = Font.PLAIN; 1719 } else { 1720 /* this string isn't any of the expected styles, so 1721 * assume its part of the font name 1722 */ 1723 styleIndex = sizeIndex; 1724 if (str.charAt(styleIndex-1) == sepChar) { 1725 styleIndex--; 1726 } 1727 } 1728 fontName = str.substring(0, styleIndex); 1729 1730 } else { 1731 int fontEnd = strlen; 1732 if (styleIndex > 0) { 1733 fontEnd = styleIndex; 1734 } else if (sizeIndex > 0) { 1735 fontEnd = sizeIndex; 1736 } 1737 if (fontEnd > 0 && str.charAt(fontEnd-1) == sepChar) { 1738 fontEnd--; 1739 } 1740 fontName = str.substring(0, fontEnd); 1741 } 1742 1743 return new Font(fontName, fontStyle, fontSize); 1744 } 1745 1746 /** 1747 * Gets the specified {@code Font} from the system properties 1748 * list. As in the {@code getProperty} method of 1749 * {@code System}, the first 1750 * argument is treated as the name of a system property to be 1751 * obtained. The {@code String} value of this property is then 1752 * interpreted as a {@code Font} object. 1753 * <p> 1754 * The property value should be one of the forms accepted by 1755 * {@code Font.decode(String)} 1756 * If the specified property is not found, or the executing code does not 1757 * have permission to read the property, the {@code font} 1758 * argument is returned instead. 1759 * @param nm the case-insensitive property name 1760 * @param font a default {@code Font} to return if property 1761 * {@code nm} is not defined 1762 * @return the {@code Font} value of the property. 1763 * @throws NullPointerException if nm is null. 1764 * @see #decode(String) 1765 */ 1766 public static Font getFont(String nm, Font font) { 1767 String str = null; 1768 try { 1769 str =System.getProperty(nm); 1770 } catch(SecurityException e) { 1771 } 1772 if (str == null) { 1773 return font; 1774 } 1775 return decode ( str ); 1776 } 1777 1778 transient int hash; 1779 /** 1780 * Returns a hashcode for this {@code Font}. 1781 * @return a hashcode value for this {@code Font}. 1782 * @since 1.0 1783 */ 1784 public int hashCode() { 1785 if (hash == 0) { 1786 hash = name.hashCode() ^ style ^ size; 1787 /* It is possible many fonts differ only in transform. 1788 * So include the transform in the hash calculation. 1789 * nonIdentityTx is set whenever there is a transform in 1790 * 'values'. The tests for null are required because it can 1791 * also be set for other reasons. 1792 */ 1793 if (nonIdentityTx && 1794 values != null && values.getTransform() != null) { 1795 hash ^= values.getTransform().hashCode(); 1796 } 1797 } 1798 return hash; 1799 } 1800 1801 /** 1802 * Compares this {@code Font} object to the specified 1803 * {@code Object}. 1804 * @param obj the {@code Object} to compare 1805 * @return {@code true} if the objects are the same 1806 * or if the argument is a {@code Font} object 1807 * describing the same font as this object; 1808 * {@code false} otherwise. 1809 * @since 1.0 1810 */ 1811 public boolean equals(Object obj) { 1812 if (obj == this) { 1813 return true; 1814 } 1815 1816 if (obj != null) { 1817 try { 1818 Font font = (Font)obj; 1819 if (size == font.size && 1820 style == font.style && 1821 nonIdentityTx == font.nonIdentityTx && 1822 hasLayoutAttributes == font.hasLayoutAttributes && 1823 pointSize == font.pointSize && 1824 name.equals(font.name)) { 1825 1826 /* 'values' is usually initialized lazily, except when 1827 * the font is constructed from a Map, or derived using 1828 * a Map or other values. So if only one font has 1829 * the field initialized we need to initialize it in 1830 * the other instance and compare. 1831 */ 1832 if (values == null) { 1833 if (font.values == null) { 1834 return true; 1835 } else { 1836 return getAttributeValues().equals(font.values); 1837 } 1838 } else { 1839 return values.equals(font.getAttributeValues()); 1840 } 1841 } 1842 } 1843 catch (ClassCastException e) { 1844 } 1845 } 1846 return false; 1847 } 1848 1849 /** 1850 * Converts this {@code Font} object to a {@code String} 1851 * representation. 1852 * @return a {@code String} representation of this 1853 * {@code Font} object. 1854 * @since 1.0 1855 */ 1856 // NOTE: This method may be called by privileged threads. 1857 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 1858 public String toString() { 1859 String strStyle; 1860 1861 if (isBold()) { 1862 strStyle = isItalic() ? "bolditalic" : "bold"; 1863 } else { 1864 strStyle = isItalic() ? "italic" : "plain"; 1865 } 1866 1867 return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" + 1868 strStyle + ",size=" + size + "]"; 1869 } // toString() 1870 1871 1872 /** Serialization support. A {@code readObject} 1873 * method is necessary because the constructor creates 1874 * the font's peer, and we can't serialize the peer. 1875 * Similarly the computed font "family" may be different 1876 * at {@code readObject} time than at 1877 * {@code writeObject} time. An integer version is 1878 * written so that future versions of this class will be 1879 * able to recognize serialized output from this one. 1880 */ 1881 /** 1882 * The {@code Font} Serializable Data Form. 1883 * 1884 * @serial 1885 */ 1886 private int fontSerializedDataVersion = 1; 1887 1888 /** 1889 * Writes default serializable fields to a stream. 1890 * 1891 * @param s the {@code ObjectOutputStream} to write 1892 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 1893 * @see #readObject(java.io.ObjectInputStream) 1894 */ 1895 private void writeObject(java.io.ObjectOutputStream s) 1896 throws java.lang.ClassNotFoundException, 1897 java.io.IOException 1898 { 1899 if (values != null) { 1900 synchronized(values) { 1901 // transient 1902 fRequestedAttributes = values.toSerializableHashtable(); 1903 s.defaultWriteObject(); 1904 fRequestedAttributes = null; 1905 } 1906 } else { 1907 s.defaultWriteObject(); 1908 } 1909 } 1910 1911 /** 1912 * Reads the {@code ObjectInputStream}. 1913 * Unrecognized keys or values will be ignored. 1914 * 1915 * @param s the {@code ObjectInputStream} to read 1916 * @serial 1917 * @see #writeObject(java.io.ObjectOutputStream) 1918 */ 1919 private void readObject(java.io.ObjectInputStream s) 1920 throws java.lang.ClassNotFoundException, 1921 java.io.IOException 1922 { 1923 s.defaultReadObject(); 1924 if (pointSize == 0) { 1925 pointSize = (float)size; 1926 } 1927 1928 // Handle fRequestedAttributes. 1929 // in 1.5, we always streamed out the font values plus 1930 // TRANSFORM, SUPERSCRIPT, and WIDTH, regardless of whether the 1931 // values were default or not. In 1.6 we only stream out 1932 // defined values. So, 1.6 streams in from a 1.5 stream, 1933 // it check each of these values and 'undefines' it if the 1934 // value is the default. 1935 1936 if (fRequestedAttributes != null) { 1937 values = getAttributeValues(); // init 1938 AttributeValues extras = 1939 AttributeValues.fromSerializableHashtable(fRequestedAttributes); 1940 if (!AttributeValues.is16Hashtable(fRequestedAttributes)) { 1941 extras.unsetDefault(); // if legacy stream, undefine these 1942 } 1943 values = getAttributeValues().merge(extras); 1944 this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); 1945 this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); 1946 1947 fRequestedAttributes = null; // don't need it any more 1948 } 1949 } 1950 1951 /** 1952 * Returns the number of glyphs in this {@code Font}. Glyph codes 1953 * for this {@code Font} range from 0 to 1954 * {@code getNumGlyphs()} - 1. 1955 * @return the number of glyphs in this {@code Font}. 1956 * @since 1.2 1957 */ 1958 public int getNumGlyphs() { 1959 return getFont2D().getNumGlyphs(); 1960 } 1961 1962 /** 1963 * Returns the glyphCode which is used when this {@code Font} 1964 * does not have a glyph for a specified unicode code point. 1965 * @return the glyphCode of this {@code Font}. 1966 * @since 1.2 1967 */ 1968 public int getMissingGlyphCode() { 1969 return getFont2D().getMissingGlyphCode(); 1970 } 1971 1972 /** 1973 * Returns the baseline appropriate for displaying this character. 1974 * <p> 1975 * Large fonts can support different writing systems, and each system can 1976 * use a different baseline. 1977 * The character argument determines the writing system to use. Clients 1978 * should not assume all characters use the same baseline. 1979 * 1980 * @param c a character used to identify the writing system 1981 * @return the baseline appropriate for the specified character. 1982 * @see LineMetrics#getBaselineOffsets 1983 * @see #ROMAN_BASELINE 1984 * @see #CENTER_BASELINE 1985 * @see #HANGING_BASELINE 1986 * @since 1.2 1987 */ 1988 public byte getBaselineFor(char c) { 1989 return getFont2D().getBaselineFor(c); 1990 } 1991 1992 /** 1993 * Returns a map of font attributes available in this 1994 * {@code Font}. Attributes include things like ligatures and 1995 * glyph substitution. 1996 * @return the attributes map of this {@code Font}. 1997 */ 1998 public Map<TextAttribute,?> getAttributes(){ 1999 return new AttributeMap(getAttributeValues()); 2000 } 2001 2002 /** 2003 * Returns the keys of all the attributes supported by this 2004 * {@code Font}. These attributes can be used to derive other 2005 * fonts. 2006 * @return an array containing the keys of all the attributes 2007 * supported by this {@code Font}. 2008 * @since 1.2 2009 */ 2010 public Attribute[] getAvailableAttributes() { 2011 // FONT is not supported by Font 2012 2013 Attribute attributes[] = { 2014 TextAttribute.FAMILY, 2015 TextAttribute.WEIGHT, 2016 TextAttribute.WIDTH, 2017 TextAttribute.POSTURE, 2018 TextAttribute.SIZE, 2019 TextAttribute.TRANSFORM, 2020 TextAttribute.SUPERSCRIPT, 2021 TextAttribute.CHAR_REPLACEMENT, 2022 TextAttribute.FOREGROUND, 2023 TextAttribute.BACKGROUND, 2024 TextAttribute.UNDERLINE, 2025 TextAttribute.STRIKETHROUGH, 2026 TextAttribute.RUN_DIRECTION, 2027 TextAttribute.BIDI_EMBEDDING, 2028 TextAttribute.JUSTIFICATION, 2029 TextAttribute.INPUT_METHOD_HIGHLIGHT, 2030 TextAttribute.INPUT_METHOD_UNDERLINE, 2031 TextAttribute.SWAP_COLORS, 2032 TextAttribute.NUMERIC_SHAPING, 2033 TextAttribute.KERNING, 2034 TextAttribute.LIGATURES, 2035 TextAttribute.TRACKING, 2036 }; 2037 2038 return attributes; 2039 } 2040 2041 /** 2042 * Creates a new {@code Font} object by replicating this 2043 * {@code Font} object and applying a new style and size. 2044 * @param style the style for the new {@code Font} 2045 * @param size the size for the new {@code Font} 2046 * @return a new {@code Font} object. 2047 * @since 1.2 2048 */ 2049 public Font deriveFont(int style, float size){ 2050 if (values == null) { 2051 return new Font(name, style, size, createdFont, font2DHandle); 2052 } 2053 AttributeValues newValues = getAttributeValues().clone(); 2054 int oldStyle = (this.style != style) ? this.style : -1; 2055 applyStyle(style, newValues); 2056 newValues.setSize(size); 2057 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 2058 } 2059 2060 /** 2061 * Creates a new {@code Font} object by replicating this 2062 * {@code Font} object and applying a new style and transform. 2063 * @param style the style for the new {@code Font} 2064 * @param trans the {@code AffineTransform} associated with the 2065 * new {@code Font} 2066 * @return a new {@code Font} object. 2067 * @throws IllegalArgumentException if {@code trans} is 2068 * {@code null} 2069 * @since 1.2 2070 */ 2071 public Font deriveFont(int style, AffineTransform trans){ 2072 AttributeValues newValues = getAttributeValues().clone(); 2073 int oldStyle = (this.style != style) ? this.style : -1; 2074 applyStyle(style, newValues); 2075 applyTransform(trans, newValues); 2076 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 2077 } 2078 2079 /** 2080 * Creates a new {@code Font} object by replicating the current 2081 * {@code Font} object and applying a new size to it. 2082 * @param size the size for the new {@code Font}. 2083 * @return a new {@code Font} object. 2084 * @since 1.2 2085 */ 2086 public Font deriveFont(float size){ 2087 if (values == null) { 2088 return new Font(name, style, size, createdFont, font2DHandle); 2089 } 2090 AttributeValues newValues = getAttributeValues().clone(); 2091 newValues.setSize(size); 2092 return new Font(newValues, null, -1, createdFont, font2DHandle); 2093 } 2094 2095 /** 2096 * Creates a new {@code Font} object by replicating the current 2097 * {@code Font} object and applying a new transform to it. 2098 * @param trans the {@code AffineTransform} associated with the 2099 * new {@code Font} 2100 * @return a new {@code Font} object. 2101 * @throws IllegalArgumentException if {@code trans} is 2102 * {@code null} 2103 * @since 1.2 2104 */ 2105 public Font deriveFont(AffineTransform trans){ 2106 AttributeValues newValues = getAttributeValues().clone(); 2107 applyTransform(trans, newValues); 2108 return new Font(newValues, null, -1, createdFont, font2DHandle); 2109 } 2110 2111 /** 2112 * Creates a new {@code Font} object by replicating the current 2113 * {@code Font} object and applying a new style to it. 2114 * @param style the style for the new {@code Font} 2115 * @return a new {@code Font} object. 2116 * @since 1.2 2117 */ 2118 public Font deriveFont(int style){ 2119 if (values == null) { 2120 return new Font(name, style, size, createdFont, font2DHandle); 2121 } 2122 AttributeValues newValues = getAttributeValues().clone(); 2123 int oldStyle = (this.style != style) ? this.style : -1; 2124 applyStyle(style, newValues); 2125 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 2126 } 2127 2128 /** 2129 * Creates a new {@code Font} object by replicating the current 2130 * {@code Font} object and applying a new set of font attributes 2131 * to it. 2132 * 2133 * @param attributes a map of attributes enabled for the new 2134 * {@code Font} 2135 * @return a new {@code Font} object. 2136 * @since 1.2 2137 */ 2138 public Font deriveFont(Map<? extends Attribute, ?> attributes) { 2139 if (attributes == null) { 2140 return this; 2141 } 2142 AttributeValues newValues = getAttributeValues().clone(); 2143 newValues.merge(attributes, RECOGNIZED_MASK); 2144 2145 return new Font(newValues, name, style, createdFont, font2DHandle); 2146 } 2147 2148 /** 2149 * Checks if this {@code Font} has a glyph for the specified 2150 * character. 2151 * 2152 * <p> <b>Note:</b> This method cannot handle <a 2153 * href="../../java/lang/Character.html#supplementary"> supplementary 2154 * characters</a>. To support all Unicode characters, including 2155 * supplementary characters, use the {@link #canDisplay(int)} 2156 * method or {@code canDisplayUpTo} methods. 2157 * 2158 * @param c the character for which a glyph is needed 2159 * @return {@code true} if this {@code Font} has a glyph for this 2160 * character; {@code false} otherwise. 2161 * @since 1.2 2162 */ 2163 public boolean canDisplay(char c){ 2164 return getFont2D().canDisplay(c); 2165 } 2166 2167 /** 2168 * Checks if this {@code Font} has a glyph for the specified 2169 * character. 2170 * 2171 * @param codePoint the character (Unicode code point) for which a glyph 2172 * is needed. 2173 * @return {@code true} if this {@code Font} has a glyph for the 2174 * character; {@code false} otherwise. 2175 * @throws IllegalArgumentException if the code point is not a valid Unicode 2176 * code point. 2177 * @see Character#isValidCodePoint(int) 2178 * @since 1.5 2179 */ 2180 public boolean canDisplay(int codePoint) { 2181 if (!Character.isValidCodePoint(codePoint)) { 2182 throw new IllegalArgumentException("invalid code point: " + 2183 Integer.toHexString(codePoint)); 2184 } 2185 return getFont2D().canDisplay(codePoint); 2186 } 2187 2188 /** 2189 * Indicates whether or not this {@code Font} can display a 2190 * specified {@code String}. For strings with Unicode encoding, 2191 * it is important to know if a particular font can display the 2192 * string. This method returns an offset into the {@code String} 2193 * {@code str} which is the first character this 2194 * {@code Font} cannot display without using the missing glyph 2195 * code. If the {@code Font} can display all characters, -1 is 2196 * returned. 2197 * @param str a {@code String} object 2198 * @return an offset into {@code str} that points 2199 * to the first character in {@code str} that this 2200 * {@code Font} cannot display; or {@code -1} if 2201 * this {@code Font} can display all characters in 2202 * {@code str}. 2203 * @since 1.2 2204 */ 2205 public int canDisplayUpTo(String str) { 2206 Font2D font2d = getFont2D(); 2207 int len = str.length(); 2208 for (int i = 0; i < len; i++) { 2209 char c = str.charAt(i); 2210 if (font2d.canDisplay(c)) { 2211 continue; 2212 } 2213 if (!Character.isHighSurrogate(c)) { 2214 return i; 2215 } 2216 if (!font2d.canDisplay(str.codePointAt(i))) { 2217 return i; 2218 } 2219 i++; 2220 } 2221 return -1; 2222 } 2223 2224 /** 2225 * Indicates whether or not this {@code Font} can display 2226 * the characters in the specified {@code text} 2227 * starting at {@code start} and ending at 2228 * {@code limit}. This method is a convenience overload. 2229 * @param text the specified array of {@code char} values 2230 * @param start the specified starting offset (in 2231 * {@code char}s) into the specified array of 2232 * {@code char} values 2233 * @param limit the specified ending offset (in 2234 * {@code char}s) into the specified array of 2235 * {@code char} values 2236 * @return an offset into {@code text} that points 2237 * to the first character in {@code text} that this 2238 * {@code Font} cannot display; or {@code -1} if 2239 * this {@code Font} can display all characters in 2240 * {@code text}. 2241 * @since 1.2 2242 */ 2243 public int canDisplayUpTo(char[] text, int start, int limit) { 2244 Font2D font2d = getFont2D(); 2245 for (int i = start; i < limit; i++) { 2246 char c = text[i]; 2247 if (font2d.canDisplay(c)) { 2248 continue; 2249 } 2250 if (!Character.isHighSurrogate(c)) { 2251 return i; 2252 } 2253 if (!font2d.canDisplay(Character.codePointAt(text, i, limit))) { 2254 return i; 2255 } 2256 i++; 2257 } 2258 return -1; 2259 } 2260 2261 /** 2262 * Indicates whether or not this {@code Font} can display the 2263 * text specified by the {@code iter} starting at 2264 * {@code start} and ending at {@code limit}. 2265 * 2266 * @param iter a {@link CharacterIterator} object 2267 * @param start the specified starting offset into the specified 2268 * {@code CharacterIterator}. 2269 * @param limit the specified ending offset into the specified 2270 * {@code CharacterIterator}. 2271 * @return an offset into {@code iter} that points 2272 * to the first character in {@code iter} that this 2273 * {@code Font} cannot display; or {@code -1} if 2274 * this {@code Font} can display all characters in 2275 * {@code iter}. 2276 * @since 1.2 2277 */ 2278 public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { 2279 Font2D font2d = getFont2D(); 2280 char c = iter.setIndex(start); 2281 for (int i = start; i < limit; i++, c = iter.next()) { 2282 if (font2d.canDisplay(c)) { 2283 continue; 2284 } 2285 if (!Character.isHighSurrogate(c)) { 2286 return i; 2287 } 2288 char c2 = iter.next(); 2289 // c2 could be CharacterIterator.DONE which is not a low surrogate. 2290 if (!Character.isLowSurrogate(c2)) { 2291 return i; 2292 } 2293 if (!font2d.canDisplay(Character.toCodePoint(c, c2))) { 2294 return i; 2295 } 2296 i++; 2297 } 2298 return -1; 2299 } 2300 2301 /** 2302 * Returns the italic angle of this {@code Font}. The italic angle 2303 * is the inverse slope of the caret which best matches the posture of this 2304 * {@code Font}. 2305 * @see TextAttribute#POSTURE 2306 * @return the angle of the ITALIC style of this {@code Font}. 2307 */ 2308 public float getItalicAngle() { 2309 return getItalicAngle(null); 2310 } 2311 2312 /* The FRC hints don't affect the value of the italic angle but 2313 * we need to pass them in to look up a strike. 2314 * If we can pass in ones already being used it can prevent an extra 2315 * strike from being allocated. Note that since italic angle is 2316 * a property of the font, the font transform is needed not the 2317 * device transform. Finally, this is private but the only caller of this 2318 * in the JDK - and the only likely caller - is in this same class. 2319 */ 2320 private float getItalicAngle(FontRenderContext frc) { 2321 Object aa, fm; 2322 if (frc == null) { 2323 aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; 2324 fm = RenderingHints.VALUE_FRACTIONALMETRICS_OFF; 2325 } else { 2326 aa = frc.getAntiAliasingHint(); 2327 fm = frc.getFractionalMetricsHint(); 2328 } 2329 return getFont2D().getItalicAngle(this, identityTx, aa, fm); 2330 } 2331 2332 /** 2333 * Checks whether or not this {@code Font} has uniform 2334 * line metrics. A logical {@code Font} might be a 2335 * composite font, which means that it is composed of different 2336 * physical fonts to cover different code ranges. Each of these 2337 * fonts might have different {@code LineMetrics}. If the 2338 * logical {@code Font} is a single 2339 * font then the metrics would be uniform. 2340 * @return {@code true} if this {@code Font} has 2341 * uniform line metrics; {@code false} otherwise. 2342 */ 2343 public boolean hasUniformLineMetrics() { 2344 return false; // REMIND always safe, but prevents caller optimize 2345 } 2346 2347 private transient SoftReference<FontLineMetrics> flmref; 2348 private FontLineMetrics defaultLineMetrics(FontRenderContext frc) { 2349 FontLineMetrics flm = null; 2350 if (flmref == null 2351 || (flm = flmref.get()) == null 2352 || !flm.frc.equals(frc)) { 2353 2354 /* The device transform in the frc is not used in obtaining line 2355 * metrics, although it probably should be: REMIND find why not? 2356 * The font transform is used but its applied in getFontMetrics, so 2357 * just pass identity here 2358 */ 2359 float [] metrics = new float[8]; 2360 getFont2D().getFontMetrics(this, identityTx, 2361 frc.getAntiAliasingHint(), 2362 frc.getFractionalMetricsHint(), 2363 metrics); 2364 float ascent = metrics[0]; 2365 float descent = metrics[1]; 2366 float leading = metrics[2]; 2367 float ssOffset = 0; 2368 if (values != null && values.getSuperscript() != 0) { 2369 ssOffset = (float)getTransform().getTranslateY(); 2370 ascent -= ssOffset; 2371 descent += ssOffset; 2372 } 2373 float height = ascent + descent + leading; 2374 2375 int baselineIndex = 0; // need real index, assumes roman for everything 2376 // need real baselines eventually 2377 float[] baselineOffsets = { 0, (descent/2f - ascent) / 2f, -ascent }; 2378 2379 float strikethroughOffset = metrics[4]; 2380 float strikethroughThickness = metrics[5]; 2381 2382 float underlineOffset = metrics[6]; 2383 float underlineThickness = metrics[7]; 2384 2385 float italicAngle = getItalicAngle(frc); 2386 2387 if (isTransformed()) { 2388 AffineTransform ctx = values.getCharTransform(); // extract rotation 2389 if (ctx != null) { 2390 Point2D.Float pt = new Point2D.Float(); 2391 pt.setLocation(0, strikethroughOffset); 2392 ctx.deltaTransform(pt, pt); 2393 strikethroughOffset = pt.y; 2394 pt.setLocation(0, strikethroughThickness); 2395 ctx.deltaTransform(pt, pt); 2396 strikethroughThickness = pt.y; 2397 pt.setLocation(0, underlineOffset); 2398 ctx.deltaTransform(pt, pt); 2399 underlineOffset = pt.y; 2400 pt.setLocation(0, underlineThickness); 2401 ctx.deltaTransform(pt, pt); 2402 underlineThickness = pt.y; 2403 } 2404 } 2405 strikethroughOffset += ssOffset; 2406 underlineOffset += ssOffset; 2407 2408 CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height, 2409 baselineIndex, baselineOffsets, 2410 strikethroughOffset, strikethroughThickness, 2411 underlineOffset, underlineThickness, 2412 ssOffset, italicAngle); 2413 2414 flm = new FontLineMetrics(0, cm, frc); 2415 flmref = new SoftReference<FontLineMetrics>(flm); 2416 } 2417 2418 return (FontLineMetrics)flm.clone(); 2419 } 2420 2421 /** 2422 * Returns a {@link LineMetrics} object created with the specified 2423 * {@code String} and {@link FontRenderContext}. 2424 * @param str the specified {@code String} 2425 * @param frc the specified {@code FontRenderContext} 2426 * @return a {@code LineMetrics} object created with the 2427 * specified {@code String} and {@link FontRenderContext}. 2428 */ 2429 public LineMetrics getLineMetrics( String str, FontRenderContext frc) { 2430 FontLineMetrics flm = defaultLineMetrics(frc); 2431 flm.numchars = str.length(); 2432 return flm; 2433 } 2434 2435 /** 2436 * Returns a {@code LineMetrics} object created with the 2437 * specified arguments. 2438 * @param str the specified {@code String} 2439 * @param beginIndex the initial offset of {@code str} 2440 * @param limit the end offset of {@code str} 2441 * @param frc the specified {@code FontRenderContext} 2442 * @return a {@code LineMetrics} object created with the 2443 * specified arguments. 2444 */ 2445 public LineMetrics getLineMetrics( String str, 2446 int beginIndex, int limit, 2447 FontRenderContext frc) { 2448 FontLineMetrics flm = defaultLineMetrics(frc); 2449 int numChars = limit - beginIndex; 2450 flm.numchars = (numChars < 0)? 0: numChars; 2451 return flm; 2452 } 2453 2454 /** 2455 * Returns a {@code LineMetrics} object created with the 2456 * specified arguments. 2457 * @param chars an array of characters 2458 * @param beginIndex the initial offset of {@code chars} 2459 * @param limit the end offset of {@code chars} 2460 * @param frc the specified {@code FontRenderContext} 2461 * @return a {@code LineMetrics} object created with the 2462 * specified arguments. 2463 */ 2464 public LineMetrics getLineMetrics(char [] chars, 2465 int beginIndex, int limit, 2466 FontRenderContext frc) { 2467 FontLineMetrics flm = defaultLineMetrics(frc); 2468 int numChars = limit - beginIndex; 2469 flm.numchars = (numChars < 0)? 0: numChars; 2470 return flm; 2471 } 2472 2473 /** 2474 * Returns a {@code LineMetrics} object created with the 2475 * specified arguments. 2476 * @param ci the specified {@code CharacterIterator} 2477 * @param beginIndex the initial offset in {@code ci} 2478 * @param limit the end offset of {@code ci} 2479 * @param frc the specified {@code FontRenderContext} 2480 * @return a {@code LineMetrics} object created with the 2481 * specified arguments. 2482 */ 2483 public LineMetrics getLineMetrics(CharacterIterator ci, 2484 int beginIndex, int limit, 2485 FontRenderContext frc) { 2486 FontLineMetrics flm = defaultLineMetrics(frc); 2487 int numChars = limit - beginIndex; 2488 flm.numchars = (numChars < 0)? 0: numChars; 2489 return flm; 2490 } 2491 2492 /** 2493 * Returns the logical bounds of the specified {@code String} in 2494 * the specified {@code FontRenderContext}. The logical bounds 2495 * contains the origin, ascent, advance, and height, which includes 2496 * the leading. The logical bounds does not always enclose all the 2497 * text. For example, in some languages and in some fonts, accent 2498 * marks can be positioned above the ascent or below the descent. 2499 * To obtain a visual bounding box, which encloses all the text, 2500 * use the {@link TextLayout#getBounds() getBounds} method of 2501 * {@code TextLayout}. 2502 * <p>Note: The returned bounds is in baseline-relative coordinates 2503 * (see {@link java.awt.Font class notes}). 2504 * @param str the specified {@code String} 2505 * @param frc the specified {@code FontRenderContext} 2506 * @return a {@link Rectangle2D} that is the bounding box of the 2507 * specified {@code String} in the specified 2508 * {@code FontRenderContext}. 2509 * @see FontRenderContext 2510 * @see Font#createGlyphVector 2511 * @since 1.2 2512 */ 2513 public Rectangle2D getStringBounds( String str, FontRenderContext frc) { 2514 char[] array = str.toCharArray(); 2515 return getStringBounds(array, 0, array.length, frc); 2516 } 2517 2518 /** 2519 * Returns the logical bounds of the specified {@code String} in 2520 * the specified {@code FontRenderContext}. The logical bounds 2521 * contains the origin, ascent, advance, and height, which includes 2522 * the leading. The logical bounds does not always enclose all the 2523 * text. For example, in some languages and in some fonts, accent 2524 * marks can be positioned above the ascent or below the descent. 2525 * To obtain a visual bounding box, which encloses all the text, 2526 * use the {@link TextLayout#getBounds() getBounds} method of 2527 * {@code TextLayout}. 2528 * <p>Note: The returned bounds is in baseline-relative coordinates 2529 * (see {@link java.awt.Font class notes}). 2530 * @param str the specified {@code String} 2531 * @param beginIndex the initial offset of {@code str} 2532 * @param limit the end offset of {@code str} 2533 * @param frc the specified {@code FontRenderContext} 2534 * @return a {@code Rectangle2D} that is the bounding box of the 2535 * specified {@code String} in the specified 2536 * {@code FontRenderContext}. 2537 * @throws IndexOutOfBoundsException if {@code beginIndex} is 2538 * less than zero, or {@code limit} is greater than the 2539 * length of {@code str}, or {@code beginIndex} 2540 * is greater than {@code limit}. 2541 * @see FontRenderContext 2542 * @see Font#createGlyphVector 2543 * @since 1.2 2544 */ 2545 public Rectangle2D getStringBounds( String str, 2546 int beginIndex, int limit, 2547 FontRenderContext frc) { 2548 String substr = str.substring(beginIndex, limit); 2549 return getStringBounds(substr, frc); 2550 } 2551 2552 /** 2553 * Returns the logical bounds of the specified array of characters 2554 * in the specified {@code FontRenderContext}. The logical 2555 * bounds contains the origin, ascent, advance, and height, which 2556 * includes the leading. The logical bounds does not always enclose 2557 * all the text. For example, in some languages and in some fonts, 2558 * accent marks can be positioned above the ascent or below the 2559 * descent. To obtain a visual bounding box, which encloses all the 2560 * text, use the {@link TextLayout#getBounds() getBounds} method of 2561 * {@code TextLayout}. 2562 * <p>Note: The returned bounds is in baseline-relative coordinates 2563 * (see {@link java.awt.Font class notes}). 2564 * @param chars an array of characters 2565 * @param beginIndex the initial offset in the array of 2566 * characters 2567 * @param limit the end offset in the array of characters 2568 * @param frc the specified {@code FontRenderContext} 2569 * @return a {@code Rectangle2D} that is the bounding box of the 2570 * specified array of characters in the specified 2571 * {@code FontRenderContext}. 2572 * @throws IndexOutOfBoundsException if {@code beginIndex} is 2573 * less than zero, or {@code limit} is greater than the 2574 * length of {@code chars}, or {@code beginIndex} 2575 * is greater than {@code limit}. 2576 * @see FontRenderContext 2577 * @see Font#createGlyphVector 2578 * @since 1.2 2579 */ 2580 public Rectangle2D getStringBounds(char [] chars, 2581 int beginIndex, int limit, 2582 FontRenderContext frc) { 2583 if (beginIndex < 0) { 2584 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); 2585 } 2586 if (limit > chars.length) { 2587 throw new IndexOutOfBoundsException("limit: " + limit); 2588 } 2589 if (beginIndex > limit) { 2590 throw new IndexOutOfBoundsException("range length: " + 2591 (limit - beginIndex)); 2592 } 2593 2594 // this code should be in textlayout 2595 // quick check for simple text, assume GV ok to use if simple 2596 2597 boolean simple = values == null || 2598 (values.getKerning() == 0 && values.getLigatures() == 0 && 2599 values.getBaselineTransform() == null); 2600 if (simple) { 2601 simple = ! FontUtilities.isComplexText(chars, beginIndex, limit); 2602 } 2603 2604 if (simple) { 2605 GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex, 2606 limit - beginIndex, frc); 2607 return gv.getLogicalBounds(); 2608 } else { 2609 // need char array constructor on textlayout 2610 String str = new String(chars, beginIndex, limit - beginIndex); 2611 TextLayout tl = new TextLayout(str, this, frc); 2612 return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(), 2613 tl.getAscent() + tl.getDescent() + 2614 tl.getLeading()); 2615 } 2616 } 2617 2618 /** 2619 * Returns the logical bounds of the characters indexed in the 2620 * specified {@link CharacterIterator} in the 2621 * specified {@code FontRenderContext}. The logical bounds 2622 * contains the origin, ascent, advance, and height, which includes 2623 * the leading. The logical bounds does not always enclose all the 2624 * text. For example, in some languages and in some fonts, accent 2625 * marks can be positioned above the ascent or below the descent. 2626 * To obtain a visual bounding box, which encloses all the text, 2627 * use the {@link TextLayout#getBounds() getBounds} method of 2628 * {@code TextLayout}. 2629 * <p>Note: The returned bounds is in baseline-relative coordinates 2630 * (see {@link java.awt.Font class notes}). 2631 * @param ci the specified {@code CharacterIterator} 2632 * @param beginIndex the initial offset in {@code ci} 2633 * @param limit the end offset in {@code ci} 2634 * @param frc the specified {@code FontRenderContext} 2635 * @return a {@code Rectangle2D} that is the bounding box of the 2636 * characters indexed in the specified {@code CharacterIterator} 2637 * in the specified {@code FontRenderContext}. 2638 * @see FontRenderContext 2639 * @see Font#createGlyphVector 2640 * @since 1.2 2641 * @throws IndexOutOfBoundsException if {@code beginIndex} is 2642 * less than the start index of {@code ci}, or 2643 * {@code limit} is greater than the end index of 2644 * {@code ci}, or {@code beginIndex} is greater 2645 * than {@code limit} 2646 */ 2647 public Rectangle2D getStringBounds(CharacterIterator ci, 2648 int beginIndex, int limit, 2649 FontRenderContext frc) { 2650 int start = ci.getBeginIndex(); 2651 int end = ci.getEndIndex(); 2652 2653 if (beginIndex < start) { 2654 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); 2655 } 2656 if (limit > end) { 2657 throw new IndexOutOfBoundsException("limit: " + limit); 2658 } 2659 if (beginIndex > limit) { 2660 throw new IndexOutOfBoundsException("range length: " + 2661 (limit - beginIndex)); 2662 } 2663 2664 char[] arr = new char[limit - beginIndex]; 2665 2666 ci.setIndex(beginIndex); 2667 for(int idx = 0; idx < arr.length; idx++) { 2668 arr[idx] = ci.current(); 2669 ci.next(); 2670 } 2671 2672 return getStringBounds(arr,0,arr.length,frc); 2673 } 2674 2675 /** 2676 * Returns the bounds for the character with the maximum 2677 * bounds as defined in the specified {@code FontRenderContext}. 2678 * <p>Note: The returned bounds is in baseline-relative coordinates 2679 * (see {@link java.awt.Font class notes}). 2680 * @param frc the specified {@code FontRenderContext} 2681 * @return a {@code Rectangle2D} that is the bounding box 2682 * for the character with the maximum bounds. 2683 */ 2684 public Rectangle2D getMaxCharBounds(FontRenderContext frc) { 2685 float [] metrics = new float[4]; 2686 2687 getFont2D().getFontMetrics(this, frc, metrics); 2688 2689 return new Rectangle2D.Float(0, -metrics[0], 2690 metrics[3], 2691 metrics[0] + metrics[1] + metrics[2]); 2692 } 2693 2694 /** 2695 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2696 * mapping characters to glyphs one-to-one based on the 2697 * Unicode cmap in this {@code Font}. This method does no other 2698 * processing besides the mapping of glyphs to characters. This 2699 * means that this method is not useful for some scripts, such 2700 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2701 * shaping, or ligature substitution. 2702 * @param frc the specified {@code FontRenderContext} 2703 * @param str the specified {@code String} 2704 * @return a new {@code GlyphVector} created with the 2705 * specified {@code String} and the specified 2706 * {@code FontRenderContext}. 2707 */ 2708 public GlyphVector createGlyphVector(FontRenderContext frc, String str) 2709 { 2710 return (GlyphVector)new StandardGlyphVector(this, str, frc); 2711 } 2712 2713 /** 2714 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2715 * mapping characters to glyphs one-to-one based on the 2716 * Unicode cmap in this {@code Font}. This method does no other 2717 * processing besides the mapping of glyphs to characters. This 2718 * means that this method is not useful for some scripts, such 2719 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2720 * shaping, or ligature substitution. 2721 * @param frc the specified {@code FontRenderContext} 2722 * @param chars the specified array of characters 2723 * @return a new {@code GlyphVector} created with the 2724 * specified array of characters and the specified 2725 * {@code FontRenderContext}. 2726 */ 2727 public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) 2728 { 2729 return (GlyphVector)new StandardGlyphVector(this, chars, frc); 2730 } 2731 2732 /** 2733 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2734 * mapping the specified characters to glyphs one-to-one based on the 2735 * Unicode cmap in this {@code Font}. This method does no other 2736 * processing besides the mapping of glyphs to characters. This 2737 * means that this method is not useful for some scripts, such 2738 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2739 * shaping, or ligature substitution. 2740 * @param frc the specified {@code FontRenderContext} 2741 * @param ci the specified {@code CharacterIterator} 2742 * @return a new {@code GlyphVector} created with the 2743 * specified {@code CharacterIterator} and the specified 2744 * {@code FontRenderContext}. 2745 */ 2746 public GlyphVector createGlyphVector( FontRenderContext frc, 2747 CharacterIterator ci) 2748 { 2749 return (GlyphVector)new StandardGlyphVector(this, ci, frc); 2750 } 2751 2752 /** 2753 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2754 * mapping characters to glyphs one-to-one based on the 2755 * Unicode cmap in this {@code Font}. This method does no other 2756 * processing besides the mapping of glyphs to characters. This 2757 * means that this method is not useful for some scripts, such 2758 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2759 * shaping, or ligature substitution. 2760 * @param frc the specified {@code FontRenderContext} 2761 * @param glyphCodes the specified integer array 2762 * @return a new {@code GlyphVector} created with the 2763 * specified integer array and the specified 2764 * {@code FontRenderContext}. 2765 */ 2766 public GlyphVector createGlyphVector( FontRenderContext frc, 2767 int [] glyphCodes) 2768 { 2769 return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc); 2770 } 2771 2772 /** 2773 * Returns a new {@code GlyphVector} object, performing full 2774 * layout of the text if possible. Full layout is required for 2775 * complex text, such as Arabic or Hindi. Support for different 2776 * scripts depends on the font and implementation. 2777 * <p> 2778 * Layout requires bidi analysis, as performed by 2779 * {@code Bidi}, and should only be performed on text that 2780 * has a uniform direction. The direction is indicated in the 2781 * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a 2782 * right-to-left (Arabic and Hebrew) run direction, or 2783 * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English) 2784 * run direction. 2785 * <p> 2786 * In addition, some operations, such as Arabic shaping, require 2787 * context, so that the characters at the start and limit can have 2788 * the proper shapes. Sometimes the data in the buffer outside 2789 * the provided range does not have valid data. The values 2790 * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be 2791 * added to the flags parameter to indicate that the text before 2792 * start, or after limit, respectively, should not be examined 2793 * for context. 2794 * <p> 2795 * All other values for the flags parameter are reserved. 2796 * 2797 * @param frc the specified {@code FontRenderContext} 2798 * @param text the text to layout 2799 * @param start the start of the text to use for the {@code GlyphVector} 2800 * @param limit the limit of the text to use for the {@code GlyphVector} 2801 * @param flags control flags as described above 2802 * @return a new {@code GlyphVector} representing the text between 2803 * start and limit, with glyphs chosen and positioned so as to best represent 2804 * the text 2805 * @throws ArrayIndexOutOfBoundsException if start or limit is 2806 * out of bounds 2807 * @see java.text.Bidi 2808 * @see #LAYOUT_LEFT_TO_RIGHT 2809 * @see #LAYOUT_RIGHT_TO_LEFT 2810 * @see #LAYOUT_NO_START_CONTEXT 2811 * @see #LAYOUT_NO_LIMIT_CONTEXT 2812 * @since 1.4 2813 */ 2814 public GlyphVector layoutGlyphVector(FontRenderContext frc, 2815 char[] text, 2816 int start, 2817 int limit, 2818 int flags) { 2819 2820 GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines 2821 StandardGlyphVector gv = gl.layout(this, frc, text, 2822 start, limit-start, flags, null); 2823 GlyphLayout.done(gl); 2824 return gv; 2825 } 2826 2827 /** 2828 * A flag to layoutGlyphVector indicating that text is left-to-right as 2829 * determined by Bidi analysis. 2830 */ 2831 public static final int LAYOUT_LEFT_TO_RIGHT = 0; 2832 2833 /** 2834 * A flag to layoutGlyphVector indicating that text is right-to-left as 2835 * determined by Bidi analysis. 2836 */ 2837 public static final int LAYOUT_RIGHT_TO_LEFT = 1; 2838 2839 /** 2840 * A flag to layoutGlyphVector indicating that text in the char array 2841 * before the indicated start should not be examined. 2842 */ 2843 public static final int LAYOUT_NO_START_CONTEXT = 2; 2844 2845 /** 2846 * A flag to layoutGlyphVector indicating that text in the char array 2847 * after the indicated limit should not be examined. 2848 */ 2849 public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; 2850 2851 2852 private static void applyTransform(AffineTransform trans, AttributeValues values) { 2853 if (trans == null) { 2854 throw new IllegalArgumentException("transform must not be null"); 2855 } 2856 values.setTransform(trans); 2857 } 2858 2859 private static void applyStyle(int style, AttributeValues values) { 2860 // WEIGHT_BOLD, WEIGHT_REGULAR 2861 values.setWeight((style & BOLD) != 0 ? 2f : 1f); 2862 // POSTURE_OBLIQUE, POSTURE_REGULAR 2863 values.setPosture((style & ITALIC) != 0 ? .2f : 0f); 2864 } 2865 2866 /* 2867 * Initialize JNI field and method IDs 2868 */ 2869 private static native void initIDs(); 2870 }