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 }
--- EOF ---