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