1 /* 2 * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 import java.awt.font.FontRenderContext; 29 import java.awt.font.GlyphVector; 30 import java.awt.font.LineMetrics; 31 import java.awt.font.TextAttribute; 32 import java.awt.font.TextLayout; 33 import java.awt.geom.AffineTransform; 34 import java.awt.geom.Point2D; 35 import java.awt.geom.Rectangle2D; 36 import java.awt.peer.FontPeer; 37 import java.io.*; 38 import java.lang.ref.SoftReference; 39 import java.nio.file.Files; 40 import java.security.AccessController; 41 import java.security.PrivilegedExceptionAction; 42 import java.text.AttributedCharacterIterator.Attribute; 43 import java.text.CharacterIterator; 44 import java.util.EventListener; 45 import java.util.Hashtable; 46 import java.util.Locale; 47 import java.util.Map; 48 49 import sun.awt.ComponentFactory; 50 import sun.font.StandardGlyphVector; 51 52 import sun.font.AttributeMap; 53 import sun.font.AttributeValues; 54 import sun.font.CompositeFont; 55 import sun.font.CreatedFontTracker; 56 import sun.font.Font2D; 57 import sun.font.Font2DHandle; 58 import sun.font.FontAccess; 59 import sun.font.FontDesignMetrics; 60 import sun.font.FontManager; 61 import sun.font.FontManagerFactory; 62 import sun.font.FontUtilities; 63 import sun.font.GlyphLayout; 64 import sun.font.FontLineMetrics; 65 import sun.font.CoreMetrics; 66 67 import static sun.font.EAttribute.*; 68 69 /** 70 * The {@code Font} class represents fonts, which are used to 71 * render text in a visible way. 72 * A font provides the information needed to map sequences of 73 * <em>characters</em> to sequences of <em>glyphs</em> 74 * and to render sequences of glyphs on {@code Graphics} and 75 * {@code Component} objects. 76 * 77 * <h2>Characters and Glyphs</h2> 78 * 79 * A <em>character</em> is a symbol that represents an item such as a letter, 80 * a digit, or punctuation in an abstract way. For example, {@code 'g'}, 81 * LATIN SMALL LETTER G, is a character. 82 * <p> 83 * A <em>glyph</em> is a shape used to render a character or a sequence of 84 * characters. In simple writing systems, such as Latin, typically one glyph 85 * represents one character. In general, however, characters and glyphs do not 86 * have one-to-one correspondence. For example, the character 'á' 87 * LATIN SMALL LETTER A WITH ACUTE, can be represented by 88 * two glyphs: one for 'a' and one for '´'. On the other hand, the 89 * two-character string "fi" can be represented by a single glyph, an 90 * "fi" ligature. In complex writing systems, such as Arabic or the South 91 * and South-East Asian writing systems, the relationship between characters 92 * and glyphs can be more complicated and involve context-dependent selection 93 * of glyphs as well as glyph reordering. 94 * 95 * A font encapsulates the collection of glyphs needed to render a selected set 96 * of characters as well as the tables needed to map sequences of characters to 97 * corresponding sequences of glyphs. 98 * 99 * <h2>Physical and Logical Fonts</h2> 100 * 101 * The Java Platform distinguishes between two kinds of fonts: 102 * <em>physical</em> fonts and <em>logical</em> fonts. 103 * <p> 104 * <em>Physical</em> fonts are the actual font libraries containing glyph data 105 * and tables to map from character sequences to glyph sequences, using a font 106 * technology such as TrueType or PostScript Type 1. 107 * All implementations of the Java Platform must support TrueType fonts; 108 * support for other font technologies is implementation dependent. 109 * Physical fonts may use names such as Helvetica, Palatino, HonMincho, or 110 * any number of other font names. 111 * Typically, each physical font supports only a limited set of writing 112 * systems, for example, only Latin characters or only Japanese and Basic 113 * Latin. 114 * The set of available physical fonts varies between configurations. 115 * Applications that require specific fonts can bundle them and instantiate 116 * them using the {@link #createFont createFont} method. 117 * <p> 118 * <em>Logical</em> fonts are the five font families defined by the Java 119 * platform which must be supported by any Java runtime environment: 120 * Serif, SansSerif, Monospaced, Dialog, and DialogInput. 121 * These logical fonts are not actual font libraries. Instead, the logical 122 * font names are mapped to physical fonts by the Java runtime environment. 123 * The mapping is implementation and usually locale dependent, so the look 124 * and the metrics provided by them vary. 125 * Typically, each logical font name maps to several physical fonts in order to 126 * cover a large range of characters. 127 * <p> 128 * Peered AWT components, such as {@link Label Label} and 129 * {@link TextField TextField}, can only use logical fonts. 130 * <p> 131 * For a discussion of the relative advantages and disadvantages of using 132 * physical or logical fonts, see the 133 * <a href="https://docs.oracle.com/javase/tutorial/2d/text/fonts.html#advantages-and-disadvantages"> 134 * Physical and Logical Fonts</a> 135 * in <a href="https://docs.oracle.com/javase/tutorial/index.html">The Java Tutorials</a> 136 * document. 137 * 138 * <h2>Font Faces and Names</h2> 139 * 140 * A {@code Font} 141 * can have many faces, such as heavy, medium, oblique, gothic and 142 * regular. All of these faces have similar typographic design. 143 * <p> 144 * There are three different names that you can get from a 145 * {@code Font} object. The <em>logical font name</em> is simply the 146 * name that was used to construct the font. 147 * The <em>font face name</em>, or just <em>font name</em> for 148 * short, is the name of a particular font face, like Helvetica Bold. The 149 * <em>family name</em> is the name of the font family that determines the 150 * typographic design across several faces, like Helvetica. 151 * <p> 152 * The {@code Font} class represents an instance of a font face from 153 * a collection of font faces that are present in the system resources 154 * of the host system. As examples, Arial Bold and Courier Bold Italic 155 * are font faces. There can be several {@code Font} objects 156 * associated with a font face, each differing in size, style, transform 157 * and font features. 158 * <p> 159 * Glyphs may not always be rendered with the requested properties (e.g, font 160 * and style) due to platform limitations such as the absence of suitable 161 * platform fonts to implement a logical font. 162 * <p> 163 * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method 164 * of the {@code GraphicsEnvironment} class returns an 165 * array of all font faces available in the system. These font faces are 166 * returned as {@code Font} objects with a size of 1, identity 167 * transform and default font features. These 168 * base fonts can then be used to derive new {@code Font} objects 169 * with varying sizes, styles, transforms and font features via the 170 * {@code deriveFont} methods in this class. 171 * 172 * <h2>Font and TextAttribute</h2> 173 * 174 * <p>{@code Font} supports most 175 * {@code TextAttribute}s. This makes some operations, such as 176 * rendering underlined text, convenient since it is not 177 * necessary to explicitly construct a {@code TextLayout} object. 178 * Attributes can be set on a Font by constructing or deriving it 179 * using a {@code Map} of {@code TextAttribute} values. 180 * 181 * <p>The values of some {@code TextAttributes} are not 182 * serializable, and therefore attempting to serialize an instance of 183 * {@code Font} that has such values will not serialize them. 184 * This means a Font deserialized from such a stream will not compare 185 * equal to the original Font that contained the non-serializable 186 * attributes. This should very rarely pose a problem 187 * since these attributes are typically used only in special 188 * circumstances and are unlikely to be serialized. 189 * 190 * <ul> 191 * <li>{@code FOREGROUND} and {@code BACKGROUND} use 192 * {@code Paint} values. The subclass {@code Color} is 193 * serializable, while {@code GradientPaint} and 194 * {@code TexturePaint} are not.</li> 195 * <li>{@code CHAR_REPLACEMENT} uses 196 * {@code GraphicAttribute} values. The subclasses 197 * {@code ShapeGraphicAttribute} and 198 * {@code ImageGraphicAttribute} are not serializable.</li> 199 * <li>{@code INPUT_METHOD_HIGHLIGHT} uses 200 * {@code InputMethodHighlight} values, which are 201 * not serializable. See {@link java.awt.im.InputMethodHighlight}.</li> 202 * </ul> 203 * 204 * <p>Clients who create custom subclasses of {@code Paint} and 205 * {@code GraphicAttribute} can make them serializable and 206 * avoid this problem. Clients who use input method highlights can 207 * convert these to the platform-specific attributes for that 208 * highlight on the current platform and set them on the Font as 209 * a workaround. 210 * 211 * <p>The {@code Map}-based constructor and 212 * {@code deriveFont} APIs ignore the FONT attribute, and it is 213 * not retained by the Font; the static {@link #getFont} method should 214 * be used if the FONT attribute might be present. See {@link 215 * java.awt.font.TextAttribute#FONT} for more information.</p> 216 * 217 * <p>Several attributes will cause additional rendering overhead 218 * and potentially invoke layout. If a {@code Font} has such 219 * attributes, the <code>{@link #hasLayoutAttributes()}</code> method 220 * will return true.</p> 221 * 222 * <p>Note: Font rotations can cause text baselines to be rotated. In 223 * order to account for this (rare) possibility, font APIs are 224 * specified to return metrics and take parameters 'in 225 * baseline-relative coordinates'. This maps the 'x' coordinate to 226 * the advance along the baseline, (positive x is forward along the 227 * baseline), and the 'y' coordinate to a distance along the 228 * perpendicular to the baseline at 'x' (positive y is 90 degrees 229 * clockwise from the baseline vector). APIs for which this is 230 * especially important are called out as having 'baseline-relative 231 * coordinates.' 232 */ 233 public class Font implements java.io.Serializable 234 { 235 private static class FontAccessImpl extends FontAccess { 236 public Font2D getFont2D(Font font) { 237 return font.getFont2D(); 238 } 239 240 public void setFont2D(Font font, Font2DHandle handle) { 241 font.font2DHandle = handle; 242 } 243 244 public void setCreatedFont(Font font) { 245 font.createdFont = true; 246 } 247 248 public boolean isCreatedFont(Font font) { 249 return font.createdFont; 250 } 251 252 @Override 253 public FontPeer getFontPeer(final Font font) { 254 return font.getFontPeer(); 255 } 256 } 257 258 static { 259 /* ensure that the necessary native libraries are loaded */ 260 Toolkit.loadLibraries(); 261 initIDs(); 262 FontAccess.setFontAccess(new FontAccessImpl()); 263 } 264 265 /** 266 * This is now only used during serialization. Typically 267 * it is null. 268 * 269 * @serial 270 * @see #getAttributes() 271 */ 272 private Hashtable<Object, Object> fRequestedAttributes; 273 274 /* 275 * Constants to be used for logical font family names. 276 */ 277 278 /** 279 * A String constant for the canonical family name of the 280 * logical font "Dialog". It is useful in Font construction 281 * to provide compile-time verification of the name. 282 * @since 1.6 283 */ 284 public static final String DIALOG = "Dialog"; 285 286 /** 287 * A String constant for the canonical family name of the 288 * logical font "DialogInput". It is useful in Font construction 289 * to provide compile-time verification of the name. 290 * @since 1.6 291 */ 292 public static final String DIALOG_INPUT = "DialogInput"; 293 294 /** 295 * A String constant for the canonical family name of the 296 * logical font "SansSerif". It is useful in Font construction 297 * to provide compile-time verification of the name. 298 * @since 1.6 299 */ 300 public static final String SANS_SERIF = "SansSerif"; 301 302 /** 303 * A String constant for the canonical family name of the 304 * logical font "Serif". It is useful in Font construction 305 * to provide compile-time verification of the name. 306 * @since 1.6 307 */ 308 public static final String SERIF = "Serif"; 309 310 /** 311 * A String constant for the canonical family name of the 312 * logical font "Monospaced". It is useful in Font construction 313 * to provide compile-time verification of the name. 314 * @since 1.6 315 */ 316 public static final String MONOSPACED = "Monospaced"; 317 318 /* 319 * Constants to be used for styles. Can be combined to mix 320 * styles. 321 */ 322 323 /** 324 * The plain style constant. 325 */ 326 public static final int PLAIN = 0; 327 328 /** 329 * The bold style constant. This can be combined with the other style 330 * constants (except PLAIN) for mixed styles. 331 */ 332 public static final int BOLD = 1; 333 334 /** 335 * The italicized style constant. This can be combined with the other 336 * style constants (except PLAIN) for mixed styles. 337 */ 338 public static final int ITALIC = 2; 339 340 /** 341 * The baseline used in most Roman scripts when laying out text. 342 */ 343 public static final int ROMAN_BASELINE = 0; 344 345 /** 346 * The baseline used in ideographic scripts like Chinese, Japanese, 347 * and Korean when laying out text. 348 */ 349 public static final int CENTER_BASELINE = 1; 350 351 /** 352 * The baseline used in Devanagari and similar scripts when laying 353 * out text. 354 */ 355 public static final int HANGING_BASELINE = 2; 356 357 /** 358 * Identify a font resource of type TRUETYPE. 359 * Used to specify a TrueType font resource to the 360 * {@link #createFont} method. 361 * The TrueType format was extended to become the OpenType 362 * format, which adds support for fonts with Postscript outlines, 363 * this tag therefore references these fonts, as well as those 364 * with TrueType outlines. 365 * @since 1.3 366 */ 367 368 public static final int TRUETYPE_FONT = 0; 369 370 /** 371 * Identify a font resource of type TYPE1. 372 * Used to specify a Type1 font resource to the 373 * {@link #createFont} method. 374 * @since 1.5 375 */ 376 public static final int TYPE1_FONT = 1; 377 378 /** 379 * The logical name of this {@code Font}, as passed to the 380 * constructor. 381 * @since 1.0 382 * 383 * @serial 384 * @see #getName 385 */ 386 protected String name; 387 388 /** 389 * The style of this {@code Font}, as passed to the constructor. 390 * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC. 391 * @since 1.0 392 * 393 * @serial 394 * @see #getStyle() 395 */ 396 protected int style; 397 398 /** 399 * The point size of this {@code Font}, rounded to integer. 400 * @since 1.0 401 * 402 * @serial 403 * @see #getSize() 404 */ 405 protected int size; 406 407 /** 408 * The point size of this {@code Font} in {@code float}. 409 * 410 * @serial 411 * @see #getSize() 412 * @see #getSize2D() 413 */ 414 protected float pointSize; 415 416 /** 417 * The platform specific font information. 418 */ 419 private transient FontPeer peer; 420 private transient long pData; // native JDK1.1 font pointer 421 private transient Font2DHandle font2DHandle; 422 423 private transient AttributeValues values; 424 private transient boolean hasLayoutAttributes; 425 426 /* 427 * If the origin of a Font is a created font then this attribute 428 * must be set on all derived fonts too. 429 */ 430 private transient boolean createdFont = false; 431 432 /* 433 * This is true if the font transform is not identity. It 434 * is used to avoid unnecessary instantiation of an AffineTransform. 435 */ 436 private transient boolean nonIdentityTx; 437 438 /* 439 * A cached value used when a transform is required for internal 440 * use. This must not be exposed to callers since AffineTransform 441 * is mutable. 442 */ 443 private static final AffineTransform identityTx = new AffineTransform(); 444 445 /* 446 * JDK 1.1 serialVersionUID 447 */ 448 private static final long serialVersionUID = -4206021311591459213L; 449 450 /** 451 * Gets the peer of this {@code Font}. 452 * 453 * @return the peer of the {@code Font}. 454 */ 455 private FontPeer getFontPeer() { 456 if(peer == null) { 457 Toolkit tk = Toolkit.getDefaultToolkit(); 458 if (tk instanceof ComponentFactory) { 459 peer = ((ComponentFactory) tk).getFontPeer(name, style); 460 } 461 } 462 return peer; 463 } 464 465 /** 466 * Return the AttributeValues object associated with this 467 * font. Most of the time, the internal object is null. 468 * If required, it will be created from the 'standard' 469 * state on the font. Only non-default values will be 470 * set in the AttributeValues object. 471 * 472 * <p>Since the AttributeValues object is mutable, and it 473 * is cached in the font, care must be taken to ensure that 474 * it is not mutated. 475 */ 476 private AttributeValues getAttributeValues() { 477 if (values == null) { 478 AttributeValues valuesTmp = new AttributeValues(); 479 valuesTmp.setFamily(name); 480 valuesTmp.setSize(pointSize); // expects the float value. 481 482 if ((style & BOLD) != 0) { 483 valuesTmp.setWeight(2); // WEIGHT_BOLD 484 } 485 486 if ((style & ITALIC) != 0) { 487 valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE 488 } 489 valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility 490 values = valuesTmp; 491 } 492 493 return values; 494 } 495 496 private Font2D getFont2D() { 497 FontManager fm = FontManagerFactory.getInstance(); 498 if (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 instanceof Font) { 1817 Font font = (Font)obj; 1818 if (size == font.size && 1819 style == font.style && 1820 nonIdentityTx == font.nonIdentityTx && 1821 hasLayoutAttributes == font.hasLayoutAttributes && 1822 pointSize == font.pointSize && 1823 name.equals(font.name)) { 1824 1825 /* 'values' is usually initialized lazily, except when 1826 * the font is constructed from a Map, or derived using 1827 * a Map or other values. So if only one font has 1828 * the field initialized we need to initialize it in 1829 * the other instance and compare. 1830 */ 1831 if (values == null) { 1832 if (font.values == null) { 1833 return true; 1834 } else { 1835 return getAttributeValues().equals(font.values); 1836 } 1837 } else { 1838 return values.equals(font.getAttributeValues()); 1839 } 1840 } 1841 } 1842 return false; 1843 } 1844 1845 /** 1846 * Converts this {@code Font} object to a {@code String} 1847 * representation. 1848 * @return a {@code String} representation of this 1849 * {@code Font} object. 1850 * @since 1.0 1851 */ 1852 // NOTE: This method may be called by privileged threads. 1853 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 1854 public String toString() { 1855 String strStyle; 1856 1857 if (isBold()) { 1858 strStyle = isItalic() ? "bolditalic" : "bold"; 1859 } else { 1860 strStyle = isItalic() ? "italic" : "plain"; 1861 } 1862 1863 return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" + 1864 strStyle + ",size=" + size + "]"; 1865 } // toString() 1866 1867 1868 /** Serialization support. A {@code readObject} 1869 * method is necessary because the constructor creates 1870 * the font's peer, and we can't serialize the peer. 1871 * Similarly the computed font "family" may be different 1872 * at {@code readObject} time than at 1873 * {@code writeObject} time. An integer version is 1874 * written so that future versions of this class will be 1875 * able to recognize serialized output from this one. 1876 */ 1877 /** 1878 * The {@code Font} Serializable Data Form. 1879 * 1880 * @serial 1881 */ 1882 private int fontSerializedDataVersion = 1; 1883 1884 /** 1885 * Writes default serializable fields to a stream. 1886 * 1887 * @param s the {@code ObjectOutputStream} to write 1888 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 1889 * @see #readObject(java.io.ObjectInputStream) 1890 */ 1891 private void writeObject(java.io.ObjectOutputStream s) 1892 throws java.io.IOException 1893 { 1894 if (values != null) { 1895 synchronized(values) { 1896 // transient 1897 fRequestedAttributes = values.toSerializableHashtable(); 1898 s.defaultWriteObject(); 1899 fRequestedAttributes = null; 1900 } 1901 } else { 1902 s.defaultWriteObject(); 1903 } 1904 } 1905 1906 /** 1907 * Reads the {@code ObjectInputStream}. 1908 * Unrecognized keys or values will be ignored. 1909 * 1910 * @param s the {@code ObjectInputStream} to read 1911 * @serial 1912 * @see #writeObject(java.io.ObjectOutputStream) 1913 */ 1914 private void readObject(java.io.ObjectInputStream s) 1915 throws java.lang.ClassNotFoundException, 1916 java.io.IOException 1917 { 1918 s.defaultReadObject(); 1919 if (pointSize == 0) { 1920 pointSize = (float)size; 1921 } 1922 1923 // Handle fRequestedAttributes. 1924 // in 1.5, we always streamed out the font values plus 1925 // TRANSFORM, SUPERSCRIPT, and WIDTH, regardless of whether the 1926 // values were default or not. In 1.6 we only stream out 1927 // defined values. So, 1.6 streams in from a 1.5 stream, 1928 // it check each of these values and 'undefines' it if the 1929 // value is the default. 1930 1931 if (fRequestedAttributes != null) { 1932 values = getAttributeValues(); // init 1933 AttributeValues extras = 1934 AttributeValues.fromSerializableHashtable(fRequestedAttributes); 1935 if (!AttributeValues.is16Hashtable(fRequestedAttributes)) { 1936 extras.unsetDefault(); // if legacy stream, undefine these 1937 } 1938 values = getAttributeValues().merge(extras); 1939 this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK); 1940 this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK); 1941 1942 fRequestedAttributes = null; // don't need it any more 1943 } 1944 } 1945 1946 /** 1947 * Returns the number of glyphs in this {@code Font}. Glyph codes 1948 * for this {@code Font} range from 0 to 1949 * {@code getNumGlyphs()} - 1. 1950 * @return the number of glyphs in this {@code Font}. 1951 * @since 1.2 1952 */ 1953 public int getNumGlyphs() { 1954 return getFont2D().getNumGlyphs(); 1955 } 1956 1957 /** 1958 * Returns the glyphCode which is used when this {@code Font} 1959 * does not have a glyph for a specified unicode code point. 1960 * @return the glyphCode of this {@code Font}. 1961 * @since 1.2 1962 */ 1963 public int getMissingGlyphCode() { 1964 return getFont2D().getMissingGlyphCode(); 1965 } 1966 1967 /** 1968 * Returns the baseline appropriate for displaying this character. 1969 * <p> 1970 * Large fonts can support different writing systems, and each system can 1971 * use a different baseline. 1972 * The character argument determines the writing system to use. Clients 1973 * should not assume all characters use the same baseline. 1974 * 1975 * @param c a character used to identify the writing system 1976 * @return the baseline appropriate for the specified character. 1977 * @see LineMetrics#getBaselineOffsets 1978 * @see #ROMAN_BASELINE 1979 * @see #CENTER_BASELINE 1980 * @see #HANGING_BASELINE 1981 * @since 1.2 1982 */ 1983 public byte getBaselineFor(char c) { 1984 return getFont2D().getBaselineFor(c); 1985 } 1986 1987 /** 1988 * Returns a map of font attributes available in this 1989 * {@code Font}. Attributes include things like ligatures and 1990 * glyph substitution. 1991 * @return the attributes map of this {@code Font}. 1992 */ 1993 public Map<TextAttribute,?> getAttributes(){ 1994 return new AttributeMap(getAttributeValues()); 1995 } 1996 1997 /** 1998 * Returns the keys of all the attributes supported by this 1999 * {@code Font}. These attributes can be used to derive other 2000 * fonts. 2001 * @return an array containing the keys of all the attributes 2002 * supported by this {@code Font}. 2003 * @since 1.2 2004 */ 2005 public Attribute[] getAvailableAttributes() { 2006 // FONT is not supported by Font 2007 2008 Attribute[] attributes = { 2009 TextAttribute.FAMILY, 2010 TextAttribute.WEIGHT, 2011 TextAttribute.WIDTH, 2012 TextAttribute.POSTURE, 2013 TextAttribute.SIZE, 2014 TextAttribute.TRANSFORM, 2015 TextAttribute.SUPERSCRIPT, 2016 TextAttribute.CHAR_REPLACEMENT, 2017 TextAttribute.FOREGROUND, 2018 TextAttribute.BACKGROUND, 2019 TextAttribute.UNDERLINE, 2020 TextAttribute.STRIKETHROUGH, 2021 TextAttribute.RUN_DIRECTION, 2022 TextAttribute.BIDI_EMBEDDING, 2023 TextAttribute.JUSTIFICATION, 2024 TextAttribute.INPUT_METHOD_HIGHLIGHT, 2025 TextAttribute.INPUT_METHOD_UNDERLINE, 2026 TextAttribute.SWAP_COLORS, 2027 TextAttribute.NUMERIC_SHAPING, 2028 TextAttribute.KERNING, 2029 TextAttribute.LIGATURES, 2030 TextAttribute.TRACKING, 2031 }; 2032 2033 return attributes; 2034 } 2035 2036 /** 2037 * Creates a new {@code Font} object by replicating this 2038 * {@code Font} object and applying a new style and size. 2039 * @param style the style for the new {@code Font} 2040 * @param size the size for the new {@code Font} 2041 * @return a new {@code Font} object. 2042 * @since 1.2 2043 */ 2044 public Font deriveFont(int style, float size){ 2045 if (values == null) { 2046 return new Font(name, style, size, createdFont, font2DHandle); 2047 } 2048 AttributeValues newValues = getAttributeValues().clone(); 2049 int oldStyle = (this.style != style) ? this.style : -1; 2050 applyStyle(style, newValues); 2051 newValues.setSize(size); 2052 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 2053 } 2054 2055 /** 2056 * Creates a new {@code Font} object by replicating this 2057 * {@code Font} object and applying a new style and transform. 2058 * @param style the style for the new {@code Font} 2059 * @param trans the {@code AffineTransform} associated with the 2060 * new {@code Font} 2061 * @return a new {@code Font} object. 2062 * @throws IllegalArgumentException if {@code trans} is 2063 * {@code null} 2064 * @since 1.2 2065 */ 2066 public Font deriveFont(int style, AffineTransform trans){ 2067 AttributeValues newValues = getAttributeValues().clone(); 2068 int oldStyle = (this.style != style) ? this.style : -1; 2069 applyStyle(style, newValues); 2070 applyTransform(trans, newValues); 2071 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 2072 } 2073 2074 /** 2075 * Creates a new {@code Font} object by replicating the current 2076 * {@code Font} object and applying a new size to it. 2077 * @param size the size for the new {@code Font}. 2078 * @return a new {@code Font} object. 2079 * @since 1.2 2080 */ 2081 public Font deriveFont(float size){ 2082 if (values == null) { 2083 return new Font(name, style, size, createdFont, font2DHandle); 2084 } 2085 AttributeValues newValues = getAttributeValues().clone(); 2086 newValues.setSize(size); 2087 return new Font(newValues, null, -1, createdFont, font2DHandle); 2088 } 2089 2090 /** 2091 * Creates a new {@code Font} object by replicating the current 2092 * {@code Font} object and applying a new transform to it. 2093 * @param trans the {@code AffineTransform} associated with the 2094 * new {@code Font} 2095 * @return a new {@code Font} object. 2096 * @throws IllegalArgumentException if {@code trans} is 2097 * {@code null} 2098 * @since 1.2 2099 */ 2100 public Font deriveFont(AffineTransform trans){ 2101 AttributeValues newValues = getAttributeValues().clone(); 2102 applyTransform(trans, newValues); 2103 return new Font(newValues, null, -1, createdFont, font2DHandle); 2104 } 2105 2106 /** 2107 * Creates a new {@code Font} object by replicating the current 2108 * {@code Font} object and applying a new style to it. 2109 * @param style the style for the new {@code Font} 2110 * @return a new {@code Font} object. 2111 * @since 1.2 2112 */ 2113 public Font deriveFont(int style){ 2114 if (values == null) { 2115 return new Font(name, style, size, createdFont, font2DHandle); 2116 } 2117 AttributeValues newValues = getAttributeValues().clone(); 2118 int oldStyle = (this.style != style) ? this.style : -1; 2119 applyStyle(style, newValues); 2120 return new Font(newValues, null, oldStyle, createdFont, font2DHandle); 2121 } 2122 2123 /** 2124 * Creates a new {@code Font} object by replicating the current 2125 * {@code Font} object and applying a new set of font attributes 2126 * to it. 2127 * 2128 * @param attributes a map of attributes enabled for the new 2129 * {@code Font} 2130 * @return a new {@code Font} object. 2131 * @since 1.2 2132 */ 2133 public Font deriveFont(Map<? extends Attribute, ?> attributes) { 2134 if (attributes == null) { 2135 return this; 2136 } 2137 AttributeValues newValues = getAttributeValues().clone(); 2138 newValues.merge(attributes, RECOGNIZED_MASK); 2139 2140 return new Font(newValues, name, style, createdFont, font2DHandle); 2141 } 2142 2143 /** 2144 * Checks if this {@code Font} has a glyph for the specified 2145 * character. 2146 * 2147 * <p> <b>Note:</b> This method cannot handle <a 2148 * href="../../../java.base/java/lang/Character.html#supplementary"> supplementary 2149 * characters</a>. To support all Unicode characters, including 2150 * supplementary characters, use the {@link #canDisplay(int)} 2151 * method or {@code canDisplayUpTo} methods. 2152 * 2153 * @param c the character for which a glyph is needed 2154 * @return {@code true} if this {@code Font} has a glyph for this 2155 * character; {@code false} otherwise. 2156 * @since 1.2 2157 */ 2158 public boolean canDisplay(char c){ 2159 return getFont2D().canDisplay(c); 2160 } 2161 2162 /** 2163 * Checks if this {@code Font} has a glyph for the specified 2164 * character. 2165 * 2166 * @param codePoint the character (Unicode code point) for which a glyph 2167 * is needed. 2168 * @return {@code true} if this {@code Font} has a glyph for the 2169 * character; {@code false} otherwise. 2170 * @throws IllegalArgumentException if the code point is not a valid Unicode 2171 * code point. 2172 * @see Character#isValidCodePoint(int) 2173 * @since 1.5 2174 */ 2175 public boolean canDisplay(int codePoint) { 2176 if (!Character.isValidCodePoint(codePoint)) { 2177 throw new IllegalArgumentException("invalid code point: " + 2178 Integer.toHexString(codePoint)); 2179 } 2180 return getFont2D().canDisplay(codePoint); 2181 } 2182 2183 /** 2184 * Indicates whether or not this {@code Font} can display a 2185 * specified {@code String}. For strings with Unicode encoding, 2186 * it is important to know if a particular font can display the 2187 * string. This method returns an offset into the {@code String} 2188 * {@code str} which is the first character this 2189 * {@code Font} cannot display without using the missing glyph 2190 * code. If the {@code Font} can display all characters, -1 is 2191 * returned. 2192 * @param str a {@code String} object 2193 * @return an offset into {@code str} that points 2194 * to the first character in {@code str} that this 2195 * {@code Font} cannot display; or {@code -1} if 2196 * this {@code Font} can display all characters in 2197 * {@code str}. 2198 * @since 1.2 2199 */ 2200 public int canDisplayUpTo(String str) { 2201 Font2D font2d = getFont2D(); 2202 int len = str.length(); 2203 for (int i = 0; i < len; i++) { 2204 char c = str.charAt(i); 2205 if (font2d.canDisplay(c)) { 2206 continue; 2207 } 2208 if (!Character.isHighSurrogate(c)) { 2209 return i; 2210 } 2211 if (!font2d.canDisplay(str.codePointAt(i))) { 2212 return i; 2213 } 2214 i++; 2215 } 2216 return -1; 2217 } 2218 2219 /** 2220 * Indicates whether or not this {@code Font} can display 2221 * the characters in the specified {@code text} 2222 * starting at {@code start} and ending at 2223 * {@code limit}. This method is a convenience overload. 2224 * @param text the specified array of {@code char} values 2225 * @param start the specified starting offset (in 2226 * {@code char}s) into the specified array of 2227 * {@code char} values 2228 * @param limit the specified ending offset (in 2229 * {@code char}s) into the specified array of 2230 * {@code char} values 2231 * @return an offset into {@code text} that points 2232 * to the first character in {@code text} that this 2233 * {@code Font} cannot display; or {@code -1} if 2234 * this {@code Font} can display all characters in 2235 * {@code text}. 2236 * @since 1.2 2237 */ 2238 public int canDisplayUpTo(char[] text, int start, int limit) { 2239 Font2D font2d = getFont2D(); 2240 for (int i = start; i < limit; i++) { 2241 char c = text[i]; 2242 if (font2d.canDisplay(c)) { 2243 continue; 2244 } 2245 if (!Character.isHighSurrogate(c)) { 2246 return i; 2247 } 2248 if (!font2d.canDisplay(Character.codePointAt(text, i, limit))) { 2249 return i; 2250 } 2251 i++; 2252 } 2253 return -1; 2254 } 2255 2256 /** 2257 * Indicates whether or not this {@code Font} can display the 2258 * text specified by the {@code iter} starting at 2259 * {@code start} and ending at {@code limit}. 2260 * 2261 * @param iter a {@link CharacterIterator} object 2262 * @param start the specified starting offset into the specified 2263 * {@code CharacterIterator}. 2264 * @param limit the specified ending offset into the specified 2265 * {@code CharacterIterator}. 2266 * @return an offset into {@code iter} that points 2267 * to the first character in {@code iter} that this 2268 * {@code Font} cannot display; or {@code -1} if 2269 * this {@code Font} can display all characters in 2270 * {@code iter}. 2271 * @since 1.2 2272 */ 2273 public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { 2274 Font2D font2d = getFont2D(); 2275 char c = iter.setIndex(start); 2276 for (int i = start; i < limit; i++, c = iter.next()) { 2277 if (font2d.canDisplay(c)) { 2278 continue; 2279 } 2280 if (!Character.isHighSurrogate(c)) { 2281 return i; 2282 } 2283 char c2 = iter.next(); 2284 // c2 could be CharacterIterator.DONE which is not a low surrogate. 2285 if (!Character.isLowSurrogate(c2)) { 2286 return i; 2287 } 2288 if (!font2d.canDisplay(Character.toCodePoint(c, c2))) { 2289 return i; 2290 } 2291 i++; 2292 } 2293 return -1; 2294 } 2295 2296 /** 2297 * Returns the italic angle of this {@code Font}. The italic angle 2298 * is the inverse slope of the caret which best matches the posture of this 2299 * {@code Font}. 2300 * @see TextAttribute#POSTURE 2301 * @return the angle of the ITALIC style of this {@code Font}. 2302 */ 2303 public float getItalicAngle() { 2304 return getItalicAngle(null); 2305 } 2306 2307 /* The FRC hints don't affect the value of the italic angle but 2308 * we need to pass them in to look up a strike. 2309 * If we can pass in ones already being used it can prevent an extra 2310 * strike from being allocated. Note that since italic angle is 2311 * a property of the font, the font transform is needed not the 2312 * device transform. Finally, this is private but the only caller of this 2313 * in the JDK - and the only likely caller - is in this same class. 2314 */ 2315 private float getItalicAngle(FontRenderContext frc) { 2316 Object aa, fm; 2317 if (frc == null) { 2318 aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; 2319 fm = RenderingHints.VALUE_FRACTIONALMETRICS_OFF; 2320 } else { 2321 aa = frc.getAntiAliasingHint(); 2322 fm = frc.getFractionalMetricsHint(); 2323 } 2324 return getFont2D().getItalicAngle(this, identityTx, aa, fm); 2325 } 2326 2327 /** 2328 * Checks whether or not this {@code Font} has uniform 2329 * line metrics. A logical {@code Font} might be a 2330 * composite font, which means that it is composed of different 2331 * physical fonts to cover different code ranges. Each of these 2332 * fonts might have different {@code LineMetrics}. If the 2333 * logical {@code Font} is a single 2334 * font then the metrics would be uniform. 2335 * @return {@code true} if this {@code Font} has 2336 * uniform line metrics; {@code false} otherwise. 2337 */ 2338 public boolean hasUniformLineMetrics() { 2339 return false; // REMIND always safe, but prevents caller optimize 2340 } 2341 2342 private transient SoftReference<FontLineMetrics> flmref; 2343 private FontLineMetrics defaultLineMetrics(FontRenderContext frc) { 2344 FontLineMetrics flm = null; 2345 if (flmref == null 2346 || (flm = flmref.get()) == null 2347 || !flm.frc.equals(frc)) { 2348 2349 /* The device transform in the frc is not used in obtaining line 2350 * metrics, although it probably should be: REMIND find why not? 2351 * The font transform is used but its applied in getFontMetrics, so 2352 * just pass identity here 2353 */ 2354 float [] metrics = new float[8]; 2355 getFont2D().getFontMetrics(this, identityTx, 2356 frc.getAntiAliasingHint(), 2357 frc.getFractionalMetricsHint(), 2358 metrics); 2359 float ascent = metrics[0]; 2360 float descent = metrics[1]; 2361 float leading = metrics[2]; 2362 float ssOffset = 0; 2363 if (values != null && values.getSuperscript() != 0) { 2364 ssOffset = (float)getTransform().getTranslateY(); 2365 ascent -= ssOffset; 2366 descent += ssOffset; 2367 } 2368 float height = ascent + descent + leading; 2369 2370 int baselineIndex = 0; // need real index, assumes roman for everything 2371 // need real baselines eventually 2372 float[] baselineOffsets = { 0, (descent/2f - ascent) / 2f, -ascent }; 2373 2374 float strikethroughOffset = metrics[4]; 2375 float strikethroughThickness = metrics[5]; 2376 2377 float underlineOffset = metrics[6]; 2378 float underlineThickness = metrics[7]; 2379 2380 float italicAngle = getItalicAngle(frc); 2381 2382 if (isTransformed()) { 2383 AffineTransform ctx = values.getCharTransform(); // extract rotation 2384 if (ctx != null) { 2385 Point2D.Float pt = new Point2D.Float(); 2386 pt.setLocation(0, strikethroughOffset); 2387 ctx.deltaTransform(pt, pt); 2388 strikethroughOffset = pt.y; 2389 pt.setLocation(0, strikethroughThickness); 2390 ctx.deltaTransform(pt, pt); 2391 strikethroughThickness = pt.y; 2392 pt.setLocation(0, underlineOffset); 2393 ctx.deltaTransform(pt, pt); 2394 underlineOffset = pt.y; 2395 pt.setLocation(0, underlineThickness); 2396 ctx.deltaTransform(pt, pt); 2397 underlineThickness = pt.y; 2398 } 2399 } 2400 strikethroughOffset += ssOffset; 2401 underlineOffset += ssOffset; 2402 2403 CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height, 2404 baselineIndex, baselineOffsets, 2405 strikethroughOffset, strikethroughThickness, 2406 underlineOffset, underlineThickness, 2407 ssOffset, italicAngle); 2408 2409 flm = new FontLineMetrics(0, cm, frc); 2410 flmref = new SoftReference<FontLineMetrics>(flm); 2411 } 2412 2413 return (FontLineMetrics)flm.clone(); 2414 } 2415 2416 /** 2417 * Returns a {@link LineMetrics} object created with the specified 2418 * {@code String} and {@link FontRenderContext}. 2419 * @param str the specified {@code String} 2420 * @param frc the specified {@code FontRenderContext} 2421 * @return a {@code LineMetrics} object created with the 2422 * specified {@code String} and {@link FontRenderContext}. 2423 */ 2424 public LineMetrics getLineMetrics( String str, FontRenderContext frc) { 2425 FontLineMetrics flm = defaultLineMetrics(frc); 2426 flm.numchars = str.length(); 2427 return flm; 2428 } 2429 2430 /** 2431 * Returns a {@code LineMetrics} object created with the 2432 * specified arguments. 2433 * @param str the specified {@code String} 2434 * @param beginIndex the initial offset of {@code str} 2435 * @param limit the end offset of {@code str} 2436 * @param frc the specified {@code FontRenderContext} 2437 * @return a {@code LineMetrics} object created with the 2438 * specified arguments. 2439 */ 2440 public LineMetrics getLineMetrics( String str, 2441 int beginIndex, int limit, 2442 FontRenderContext frc) { 2443 FontLineMetrics flm = defaultLineMetrics(frc); 2444 int numChars = limit - beginIndex; 2445 flm.numchars = (numChars < 0)? 0: numChars; 2446 return flm; 2447 } 2448 2449 /** 2450 * Returns a {@code LineMetrics} object created with the 2451 * specified arguments. 2452 * @param chars an array of characters 2453 * @param beginIndex the initial offset of {@code chars} 2454 * @param limit the end offset of {@code chars} 2455 * @param frc the specified {@code FontRenderContext} 2456 * @return a {@code LineMetrics} object created with the 2457 * specified arguments. 2458 */ 2459 public LineMetrics getLineMetrics(char [] chars, 2460 int beginIndex, int limit, 2461 FontRenderContext frc) { 2462 FontLineMetrics flm = defaultLineMetrics(frc); 2463 int numChars = limit - beginIndex; 2464 flm.numchars = (numChars < 0)? 0: numChars; 2465 return flm; 2466 } 2467 2468 /** 2469 * Returns a {@code LineMetrics} object created with the 2470 * specified arguments. 2471 * @param ci the specified {@code CharacterIterator} 2472 * @param beginIndex the initial offset in {@code ci} 2473 * @param limit the end offset of {@code ci} 2474 * @param frc the specified {@code FontRenderContext} 2475 * @return a {@code LineMetrics} object created with the 2476 * specified arguments. 2477 */ 2478 public LineMetrics getLineMetrics(CharacterIterator ci, 2479 int beginIndex, int limit, 2480 FontRenderContext frc) { 2481 FontLineMetrics flm = defaultLineMetrics(frc); 2482 int numChars = limit - beginIndex; 2483 flm.numchars = (numChars < 0)? 0: numChars; 2484 return flm; 2485 } 2486 2487 /** 2488 * Returns the logical bounds of the specified {@code String} in 2489 * the specified {@code FontRenderContext}. The logical bounds 2490 * contains the origin, ascent, advance, and height, which includes 2491 * the leading. The logical bounds does not always enclose all the 2492 * text. For example, in some languages and in some fonts, accent 2493 * marks can be positioned above the ascent or below the descent. 2494 * To obtain a visual bounding box, which encloses all the text, 2495 * use the {@link TextLayout#getBounds() getBounds} method of 2496 * {@code TextLayout}. 2497 * <p>Note: The returned bounds is in baseline-relative coordinates 2498 * (see {@link java.awt.Font class notes}). 2499 * @param str the specified {@code String} 2500 * @param frc the specified {@code FontRenderContext} 2501 * @return a {@link Rectangle2D} that is the bounding box of the 2502 * specified {@code String} in the specified 2503 * {@code FontRenderContext}. 2504 * @see FontRenderContext 2505 * @see Font#createGlyphVector 2506 * @since 1.2 2507 */ 2508 public Rectangle2D getStringBounds( String str, FontRenderContext frc) { 2509 char[] array = str.toCharArray(); 2510 return getStringBounds(array, 0, array.length, frc); 2511 } 2512 2513 /** 2514 * Returns the logical bounds of the specified {@code String} in 2515 * the specified {@code FontRenderContext}. The logical bounds 2516 * contains the origin, ascent, advance, and height, which includes 2517 * the leading. The logical bounds does not always enclose all the 2518 * text. For example, in some languages and in some fonts, accent 2519 * marks can be positioned above the ascent or below the descent. 2520 * To obtain a visual bounding box, which encloses all the text, 2521 * use the {@link TextLayout#getBounds() getBounds} method of 2522 * {@code TextLayout}. 2523 * <p>Note: The returned bounds is in baseline-relative coordinates 2524 * (see {@link java.awt.Font class notes}). 2525 * @param str the specified {@code String} 2526 * @param beginIndex the initial offset of {@code str} 2527 * @param limit the end offset of {@code str} 2528 * @param frc the specified {@code FontRenderContext} 2529 * @return a {@code Rectangle2D} that is the bounding box of the 2530 * specified {@code String} in the specified 2531 * {@code FontRenderContext}. 2532 * @throws IndexOutOfBoundsException if {@code beginIndex} is 2533 * less than zero, or {@code limit} is greater than the 2534 * length of {@code str}, or {@code beginIndex} 2535 * is greater than {@code limit}. 2536 * @see FontRenderContext 2537 * @see Font#createGlyphVector 2538 * @since 1.2 2539 */ 2540 public Rectangle2D getStringBounds( String str, 2541 int beginIndex, int limit, 2542 FontRenderContext frc) { 2543 String substr = str.substring(beginIndex, limit); 2544 return getStringBounds(substr, frc); 2545 } 2546 2547 /** 2548 * Returns the logical bounds of the specified array of characters 2549 * in the specified {@code FontRenderContext}. The logical 2550 * bounds contains the origin, ascent, advance, and height, which 2551 * includes the leading. The logical bounds does not always enclose 2552 * all the text. For example, in some languages and in some fonts, 2553 * accent marks can be positioned above the ascent or below the 2554 * descent. To obtain a visual bounding box, which encloses all the 2555 * text, use the {@link TextLayout#getBounds() getBounds} method of 2556 * {@code TextLayout}. 2557 * <p>Note: The returned bounds is in baseline-relative coordinates 2558 * (see {@link java.awt.Font class notes}). 2559 * @param chars an array of characters 2560 * @param beginIndex the initial offset in the array of 2561 * characters 2562 * @param limit the end offset in the array of characters 2563 * @param frc the specified {@code FontRenderContext} 2564 * @return a {@code Rectangle2D} that is the bounding box of the 2565 * specified array of characters in the specified 2566 * {@code FontRenderContext}. 2567 * @throws IndexOutOfBoundsException if {@code beginIndex} is 2568 * less than zero, or {@code limit} is greater than the 2569 * length of {@code chars}, or {@code beginIndex} 2570 * is greater than {@code limit}. 2571 * @see FontRenderContext 2572 * @see Font#createGlyphVector 2573 * @since 1.2 2574 */ 2575 public Rectangle2D getStringBounds(char [] chars, 2576 int beginIndex, int limit, 2577 FontRenderContext frc) { 2578 if (beginIndex < 0) { 2579 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); 2580 } 2581 if (limit > chars.length) { 2582 throw new IndexOutOfBoundsException("limit: " + limit); 2583 } 2584 if (beginIndex > limit) { 2585 throw new IndexOutOfBoundsException("range length: " + 2586 (limit - beginIndex)); 2587 } 2588 2589 // this code should be in textlayout 2590 // quick check for simple text, assume GV ok to use if simple 2591 2592 boolean simple = values == null || 2593 (values.getKerning() == 0 && values.getLigatures() == 0 && 2594 values.getBaselineTransform() == null); 2595 if (simple) { 2596 simple = ! FontUtilities.isComplexText(chars, beginIndex, limit); 2597 } 2598 2599 if (simple) { 2600 FontDesignMetrics metrics = FontDesignMetrics.getMetrics(this, frc); 2601 return metrics.getSimpleBounds(chars, beginIndex, limit-beginIndex); 2602 } else { 2603 // need char array constructor on textlayout 2604 String str = new String(chars, beginIndex, limit - beginIndex); 2605 TextLayout tl = new TextLayout(str, this, frc); 2606 return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(), 2607 tl.getAscent() + tl.getDescent() + 2608 tl.getLeading()); 2609 } 2610 } 2611 2612 /** 2613 * Returns the logical bounds of the characters indexed in the 2614 * specified {@link CharacterIterator} in the 2615 * specified {@code FontRenderContext}. The logical bounds 2616 * contains the origin, ascent, advance, and height, which includes 2617 * the leading. The logical bounds does not always enclose all the 2618 * text. For example, in some languages and in some fonts, accent 2619 * marks can be positioned above the ascent or below the descent. 2620 * To obtain a visual bounding box, which encloses all the text, 2621 * use the {@link TextLayout#getBounds() getBounds} method of 2622 * {@code TextLayout}. 2623 * <p>Note: The returned bounds is in baseline-relative coordinates 2624 * (see {@link java.awt.Font class notes}). 2625 * @param ci the specified {@code CharacterIterator} 2626 * @param beginIndex the initial offset in {@code ci} 2627 * @param limit the end offset in {@code ci} 2628 * @param frc the specified {@code FontRenderContext} 2629 * @return a {@code Rectangle2D} that is the bounding box of the 2630 * characters indexed in the specified {@code CharacterIterator} 2631 * in the specified {@code FontRenderContext}. 2632 * @see FontRenderContext 2633 * @see Font#createGlyphVector 2634 * @since 1.2 2635 * @throws IndexOutOfBoundsException if {@code beginIndex} is 2636 * less than the start index of {@code ci}, or 2637 * {@code limit} is greater than the end index of 2638 * {@code ci}, or {@code beginIndex} is greater 2639 * than {@code limit} 2640 */ 2641 public Rectangle2D getStringBounds(CharacterIterator ci, 2642 int beginIndex, int limit, 2643 FontRenderContext frc) { 2644 int start = ci.getBeginIndex(); 2645 int end = ci.getEndIndex(); 2646 2647 if (beginIndex < start) { 2648 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex); 2649 } 2650 if (limit > end) { 2651 throw new IndexOutOfBoundsException("limit: " + limit); 2652 } 2653 if (beginIndex > limit) { 2654 throw new IndexOutOfBoundsException("range length: " + 2655 (limit - beginIndex)); 2656 } 2657 2658 char[] arr = new char[limit - beginIndex]; 2659 2660 ci.setIndex(beginIndex); 2661 for(int idx = 0; idx < arr.length; idx++) { 2662 arr[idx] = ci.current(); 2663 ci.next(); 2664 } 2665 2666 return getStringBounds(arr,0,arr.length,frc); 2667 } 2668 2669 /** 2670 * Returns the bounds for the character with the maximum 2671 * bounds as defined in the specified {@code FontRenderContext}. 2672 * <p>Note: The returned bounds is in baseline-relative coordinates 2673 * (see {@link java.awt.Font class notes}). 2674 * @param frc the specified {@code FontRenderContext} 2675 * @return a {@code Rectangle2D} that is the bounding box 2676 * for the character with the maximum bounds. 2677 */ 2678 public Rectangle2D getMaxCharBounds(FontRenderContext frc) { 2679 float [] metrics = new float[4]; 2680 2681 getFont2D().getFontMetrics(this, frc, metrics); 2682 2683 return new Rectangle2D.Float(0, -metrics[0], 2684 metrics[3], 2685 metrics[0] + metrics[1] + metrics[2]); 2686 } 2687 2688 /** 2689 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2690 * mapping characters to glyphs one-to-one based on the 2691 * Unicode cmap in this {@code Font}. This method does no other 2692 * processing besides the mapping of glyphs to characters. This 2693 * means that this method is not useful for some scripts, such 2694 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2695 * shaping, or ligature substitution. 2696 * @param frc the specified {@code FontRenderContext} 2697 * @param str the specified {@code String} 2698 * @return a new {@code GlyphVector} created with the 2699 * specified {@code String} and the specified 2700 * {@code FontRenderContext}. 2701 */ 2702 public GlyphVector createGlyphVector(FontRenderContext frc, String str) 2703 { 2704 return (GlyphVector)new StandardGlyphVector(this, str, frc); 2705 } 2706 2707 /** 2708 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2709 * mapping characters to glyphs one-to-one based on the 2710 * Unicode cmap in this {@code Font}. This method does no other 2711 * processing besides the mapping of glyphs to characters. This 2712 * means that this method is not useful for some scripts, such 2713 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2714 * shaping, or ligature substitution. 2715 * @param frc the specified {@code FontRenderContext} 2716 * @param chars the specified array of characters 2717 * @return a new {@code GlyphVector} created with the 2718 * specified array of characters and the specified 2719 * {@code FontRenderContext}. 2720 */ 2721 public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) 2722 { 2723 return (GlyphVector)new StandardGlyphVector(this, chars, frc); 2724 } 2725 2726 /** 2727 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2728 * mapping the specified characters to glyphs one-to-one based on the 2729 * Unicode cmap in this {@code Font}. This method does no other 2730 * processing besides the mapping of glyphs to characters. This 2731 * means that this method is not useful for some scripts, such 2732 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2733 * shaping, or ligature substitution. 2734 * @param frc the specified {@code FontRenderContext} 2735 * @param ci the specified {@code CharacterIterator} 2736 * @return a new {@code GlyphVector} created with the 2737 * specified {@code CharacterIterator} and the specified 2738 * {@code FontRenderContext}. 2739 */ 2740 public GlyphVector createGlyphVector( FontRenderContext frc, 2741 CharacterIterator ci) 2742 { 2743 return (GlyphVector)new StandardGlyphVector(this, ci, frc); 2744 } 2745 2746 /** 2747 * Creates a {@link java.awt.font.GlyphVector GlyphVector} by 2748 * mapping characters to glyphs one-to-one based on the 2749 * Unicode cmap in this {@code Font}. This method does no other 2750 * processing besides the mapping of glyphs to characters. This 2751 * means that this method is not useful for some scripts, such 2752 * as Arabic, Hebrew, Thai, and Indic, that require reordering, 2753 * shaping, or ligature substitution. 2754 * @param frc the specified {@code FontRenderContext} 2755 * @param glyphCodes the specified integer array 2756 * @return a new {@code GlyphVector} created with the 2757 * specified integer array and the specified 2758 * {@code FontRenderContext}. 2759 */ 2760 public GlyphVector createGlyphVector( FontRenderContext frc, 2761 int [] glyphCodes) 2762 { 2763 return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc); 2764 } 2765 2766 /** 2767 * Returns a new {@code GlyphVector} object, performing full 2768 * layout of the text if possible. Full layout is required for 2769 * complex text, such as Arabic or Hindi. Support for different 2770 * scripts depends on the font and implementation. 2771 * <p> 2772 * Layout requires bidi analysis, as performed by 2773 * {@code Bidi}, and should only be performed on text that 2774 * has a uniform direction. The direction is indicated in the 2775 * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a 2776 * right-to-left (Arabic and Hebrew) run direction, or 2777 * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English) 2778 * run direction. 2779 * <p> 2780 * In addition, some operations, such as Arabic shaping, require 2781 * context, so that the characters at the start and limit can have 2782 * the proper shapes. Sometimes the data in the buffer outside 2783 * the provided range does not have valid data. The values 2784 * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be 2785 * added to the flags parameter to indicate that the text before 2786 * start, or after limit, respectively, should not be examined 2787 * for context. 2788 * <p> 2789 * All other values for the flags parameter are reserved. 2790 * 2791 * @param frc the specified {@code FontRenderContext} 2792 * @param text the text to layout 2793 * @param start the start of the text to use for the {@code GlyphVector} 2794 * @param limit the limit of the text to use for the {@code GlyphVector} 2795 * @param flags control flags as described above 2796 * @return a new {@code GlyphVector} representing the text between 2797 * start and limit, with glyphs chosen and positioned so as to best represent 2798 * the text 2799 * @throws ArrayIndexOutOfBoundsException if start or limit is 2800 * out of bounds 2801 * @see java.text.Bidi 2802 * @see #LAYOUT_LEFT_TO_RIGHT 2803 * @see #LAYOUT_RIGHT_TO_LEFT 2804 * @see #LAYOUT_NO_START_CONTEXT 2805 * @see #LAYOUT_NO_LIMIT_CONTEXT 2806 * @since 1.4 2807 */ 2808 public GlyphVector layoutGlyphVector(FontRenderContext frc, 2809 char[] text, 2810 int start, 2811 int limit, 2812 int flags) { 2813 2814 GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines 2815 StandardGlyphVector gv = gl.layout(this, frc, text, 2816 start, limit-start, flags, null); 2817 GlyphLayout.done(gl); 2818 return gv; 2819 } 2820 2821 /** 2822 * A flag to layoutGlyphVector indicating that text is left-to-right as 2823 * determined by Bidi analysis. 2824 */ 2825 public static final int LAYOUT_LEFT_TO_RIGHT = 0; 2826 2827 /** 2828 * A flag to layoutGlyphVector indicating that text is right-to-left as 2829 * determined by Bidi analysis. 2830 */ 2831 public static final int LAYOUT_RIGHT_TO_LEFT = 1; 2832 2833 /** 2834 * A flag to layoutGlyphVector indicating that text in the char array 2835 * before the indicated start should not be examined. 2836 */ 2837 public static final int LAYOUT_NO_START_CONTEXT = 2; 2838 2839 /** 2840 * A flag to layoutGlyphVector indicating that text in the char array 2841 * after the indicated limit should not be examined. 2842 */ 2843 public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; 2844 2845 2846 private static void applyTransform(AffineTransform trans, AttributeValues values) { 2847 if (trans == null) { 2848 throw new IllegalArgumentException("transform must not be null"); 2849 } 2850 values.setTransform(trans); 2851 } 2852 2853 private static void applyStyle(int style, AttributeValues values) { 2854 // WEIGHT_BOLD, WEIGHT_REGULAR 2855 values.setWeight((style & BOLD) != 0 ? 2f : 1f); 2856 // POSTURE_OBLIQUE, POSTURE_REGULAR 2857 values.setPosture((style & ITALIC) != 0 ? .2f : 0f); 2858 } 2859 2860 /* 2861 * Initialize JNI field and method IDs 2862 */ 2863 private static native void initIDs(); 2864 }