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