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