Path: blob/master/src/java.desktop/share/classes/java/awt/Font.java
41152 views
/*1* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.awt;2627import java.awt.font.FontRenderContext;28import java.awt.font.GlyphVector;29import java.awt.font.LineMetrics;30import java.awt.font.TextAttribute;31import java.awt.font.TextLayout;32import java.awt.geom.AffineTransform;33import java.awt.geom.Point2D;34import java.awt.geom.Rectangle2D;35import java.awt.peer.FontPeer;36import java.io.File;37import java.io.FileOutputStream;38import java.io.FilePermission;39import java.io.IOException;40import java.io.InputStream;41import java.io.ObjectOutputStream;42import java.io.OutputStream;43import java.io.Serial;44import java.lang.ref.SoftReference;45import java.nio.file.Files;46import java.security.AccessController;47import java.security.PrivilegedExceptionAction;48import java.text.AttributedCharacterIterator.Attribute;49import java.text.CharacterIterator;50import java.util.EventListener;51import java.util.Hashtable;52import java.util.Locale;53import java.util.Map;5455import sun.awt.ComponentFactory;56import sun.font.AttributeMap;57import sun.font.AttributeValues;58import sun.font.CompositeFont;59import sun.font.CoreMetrics;60import sun.font.CreatedFontTracker;61import sun.font.Font2D;62import sun.font.Font2DHandle;63import sun.font.FontAccess;64import sun.font.FontDesignMetrics;65import sun.font.FontLineMetrics;66import sun.font.FontManager;67import sun.font.FontManagerFactory;68import sun.font.FontUtilities;69import sun.font.GlyphLayout;70import sun.font.StandardGlyphVector;7172import static sun.font.EAttribute.EBACKGROUND;73import static sun.font.EAttribute.EBIDI_EMBEDDING;74import static sun.font.EAttribute.ECHAR_REPLACEMENT;75import static sun.font.EAttribute.EFAMILY;76import static sun.font.EAttribute.EFONT;77import static sun.font.EAttribute.EFOREGROUND;78import static sun.font.EAttribute.EINPUT_METHOD_HIGHLIGHT;79import static sun.font.EAttribute.EINPUT_METHOD_UNDERLINE;80import static sun.font.EAttribute.EJUSTIFICATION;81import static sun.font.EAttribute.EKERNING;82import static sun.font.EAttribute.ELIGATURES;83import static sun.font.EAttribute.ENUMERIC_SHAPING;84import static sun.font.EAttribute.EPOSTURE;85import static sun.font.EAttribute.ERUN_DIRECTION;86import static sun.font.EAttribute.ESIZE;87import static sun.font.EAttribute.ESTRIKETHROUGH;88import static sun.font.EAttribute.ESUPERSCRIPT;89import static sun.font.EAttribute.ESWAP_COLORS;90import static sun.font.EAttribute.ETRACKING;91import static sun.font.EAttribute.ETRANSFORM;92import static sun.font.EAttribute.EUNDERLINE;93import static sun.font.EAttribute.EWEIGHT;94import static sun.font.EAttribute.EWIDTH;9596/**97* The {@code Font} class represents fonts, which are used to98* render text in a visible way.99* A font provides the information needed to map sequences of100* <em>characters</em> to sequences of <em>glyphs</em>101* and to render sequences of glyphs on {@code Graphics} and102* {@code Component} objects.103*104* <h2>Characters and Glyphs</h2>105*106* A <em>character</em> is a symbol that represents an item such as a letter,107* a digit, or punctuation in an abstract way. For example, {@code 'g'},108* LATIN SMALL LETTER G, is a character.109* <p>110* A <em>glyph</em> is a shape used to render a character or a sequence of111* characters. In simple writing systems, such as Latin, typically one glyph112* represents one character. In general, however, characters and glyphs do not113* have one-to-one correspondence. For example, the character 'á'114* LATIN SMALL LETTER A WITH ACUTE, can be represented by115* two glyphs: one for 'a' and one for '´'. On the other hand, the116* two-character string "fi" can be represented by a single glyph, an117* "fi" ligature. In complex writing systems, such as Arabic or the South118* and South-East Asian writing systems, the relationship between characters119* and glyphs can be more complicated and involve context-dependent selection120* of glyphs as well as glyph reordering.121*122* A font encapsulates the collection of glyphs needed to render a selected set123* of characters as well as the tables needed to map sequences of characters to124* corresponding sequences of glyphs.125*126* <h2>Physical and Logical Fonts</h2>127*128* The Java Platform distinguishes between two kinds of fonts:129* <em>physical</em> fonts and <em>logical</em> fonts.130* <p>131* <em>Physical</em> fonts are the actual font libraries containing glyph data132* and tables to map from character sequences to glyph sequences, using a font133* technology such as TrueType or PostScript Type 1.134* All implementations of the Java Platform must support TrueType fonts;135* support for other font technologies is implementation dependent.136* Physical fonts may use names such as Helvetica, Palatino, HonMincho, or137* any number of other font names.138* Typically, each physical font supports only a limited set of writing139* systems, for example, only Latin characters or only Japanese and Basic140* Latin.141* The set of available physical fonts varies between configurations.142* Applications that require specific fonts can bundle them and instantiate143* them using the {@link #createFont createFont} method.144* <p>145* <em>Logical</em> fonts are the five font families defined by the Java146* platform which must be supported by any Java runtime environment:147* Serif, SansSerif, Monospaced, Dialog, and DialogInput.148* These logical fonts are not actual font libraries. Instead, the logical149* font names are mapped to physical fonts by the Java runtime environment.150* The mapping is implementation and usually locale dependent, so the look151* and the metrics provided by them vary.152* Typically, each logical font name maps to several physical fonts in order to153* cover a large range of characters.154* <p>155* Peered AWT components, such as {@link Label Label} and156* {@link TextField TextField}, can only use logical fonts.157* <p>158* For a discussion of the relative advantages and disadvantages of using159* physical or logical fonts, see the160* <a href="https://docs.oracle.com/javase/tutorial/2d/text/fonts.html#advantages-and-disadvantages">161* Physical and Logical Fonts</a>162* in <a href="https://docs.oracle.com/javase/tutorial/index.html">The Java Tutorials</a>163* document.164*165* <h2>Font Faces and Names</h2>166*167* A {@code Font}168* can have many faces, such as heavy, medium, oblique, gothic and169* regular. All of these faces have similar typographic design.170* <p>171* There are three different names that you can get from a172* {@code Font} object. The <em>logical font name</em> is simply the173* name that was used to construct the font.174* The <em>font face name</em>, or just <em>font name</em> for175* short, is the name of a particular font face, like Helvetica Bold. The176* <em>family name</em> is the name of the font family that determines the177* typographic design across several faces, like Helvetica.178* <p>179* The {@code Font} class represents an instance of a font face from180* a collection of font faces that are present in the system resources181* of the host system. As examples, Arial Bold and Courier Bold Italic182* are font faces. There can be several {@code Font} objects183* associated with a font face, each differing in size, style, transform184* and font features.185* <p>186* Glyphs may not always be rendered with the requested properties (e.g, font187* and style) due to platform limitations such as the absence of suitable188* platform fonts to implement a logical font.189* <p>190* The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method191* of the {@code GraphicsEnvironment} class returns an192* array of all font faces available in the system. These font faces are193* returned as {@code Font} objects with a size of 1, identity194* transform and default font features. These195* base fonts can then be used to derive new {@code Font} objects196* with varying sizes, styles, transforms and font features via the197* {@code deriveFont} methods in this class.198*199* <h2>Font and TextAttribute</h2>200*201* <p>{@code Font} supports most202* {@code TextAttribute}s. This makes some operations, such as203* rendering underlined text, convenient since it is not204* necessary to explicitly construct a {@code TextLayout} object.205* Attributes can be set on a Font by constructing or deriving it206* using a {@code Map} of {@code TextAttribute} values.207*208* <p>The values of some {@code TextAttributes} are not209* serializable, and therefore attempting to serialize an instance of210* {@code Font} that has such values will not serialize them.211* This means a Font deserialized from such a stream will not compare212* equal to the original Font that contained the non-serializable213* attributes. This should very rarely pose a problem214* since these attributes are typically used only in special215* circumstances and are unlikely to be serialized.216*217* <ul>218* <li>{@code FOREGROUND} and {@code BACKGROUND} use219* {@code Paint} values. The subclass {@code Color} is220* serializable, while {@code GradientPaint} and221* {@code TexturePaint} are not.</li>222* <li>{@code CHAR_REPLACEMENT} uses223* {@code GraphicAttribute} values. The subclasses224* {@code ShapeGraphicAttribute} and225* {@code ImageGraphicAttribute} are not serializable.</li>226* <li>{@code INPUT_METHOD_HIGHLIGHT} uses227* {@code InputMethodHighlight} values, which are228* not serializable. See {@link java.awt.im.InputMethodHighlight}.</li>229* </ul>230*231* <p>Clients who create custom subclasses of {@code Paint} and232* {@code GraphicAttribute} can make them serializable and233* avoid this problem. Clients who use input method highlights can234* convert these to the platform-specific attributes for that235* highlight on the current platform and set them on the Font as236* a workaround.237*238* <p>The {@code Map}-based constructor and239* {@code deriveFont} APIs ignore the FONT attribute, and it is240* not retained by the Font; the static {@link #getFont} method should241* be used if the FONT attribute might be present. See {@link242* java.awt.font.TextAttribute#FONT} for more information.</p>243*244* <p>Several attributes will cause additional rendering overhead245* and potentially invoke layout. If a {@code Font} has such246* attributes, the <code>{@link #hasLayoutAttributes()}</code> method247* will return true.</p>248*249* <p>Note: Font rotations can cause text baselines to be rotated. In250* order to account for this (rare) possibility, font APIs are251* specified to return metrics and take parameters 'in252* baseline-relative coordinates'. This maps the 'x' coordinate to253* the advance along the baseline, (positive x is forward along the254* baseline), and the 'y' coordinate to a distance along the255* perpendicular to the baseline at 'x' (positive y is 90 degrees256* clockwise from the baseline vector). APIs for which this is257* especially important are called out as having 'baseline-relative258* coordinates.'259*/260public class Font implements java.io.Serializable261{262private static class FontAccessImpl extends FontAccess {263public Font2D getFont2D(Font font) {264return font.getFont2D();265}266267public void setFont2D(Font font, Font2DHandle handle) {268font.font2DHandle = handle;269}270271public void setCreatedFont(Font font) {272font.createdFont = true;273}274275public boolean isCreatedFont(Font font) {276return font.createdFont;277}278279@Override280public FontPeer getFontPeer(final Font font) {281return font.getFontPeer();282}283}284285static {286/* ensure that the necessary native libraries are loaded */287Toolkit.loadLibraries();288initIDs();289FontAccess.setFontAccess(new FontAccessImpl());290}291292/**293* This is now only used during serialization. Typically294* it is null.295*296* @serial297* @see #getAttributes()298*/299private Hashtable<Object, Object> fRequestedAttributes;300301/*302* Constants to be used for logical font family names.303*/304305/**306* A String constant for the canonical family name of the307* logical font "Dialog". It is useful in Font construction308* to provide compile-time verification of the name.309* @since 1.6310*/311public static final String DIALOG = "Dialog";312313/**314* A String constant for the canonical family name of the315* logical font "DialogInput". It is useful in Font construction316* to provide compile-time verification of the name.317* @since 1.6318*/319public static final String DIALOG_INPUT = "DialogInput";320321/**322* A String constant for the canonical family name of the323* logical font "SansSerif". It is useful in Font construction324* to provide compile-time verification of the name.325* @since 1.6326*/327public static final String SANS_SERIF = "SansSerif";328329/**330* A String constant for the canonical family name of the331* logical font "Serif". It is useful in Font construction332* to provide compile-time verification of the name.333* @since 1.6334*/335public static final String SERIF = "Serif";336337/**338* A String constant for the canonical family name of the339* logical font "Monospaced". It is useful in Font construction340* to provide compile-time verification of the name.341* @since 1.6342*/343public static final String MONOSPACED = "Monospaced";344345/*346* Constants to be used for styles. Can be combined to mix347* styles.348*/349350/**351* The plain style constant.352*/353public static final int PLAIN = 0;354355/**356* The bold style constant. This can be combined with the other style357* constants (except PLAIN) for mixed styles.358*/359public static final int BOLD = 1;360361/**362* The italicized style constant. This can be combined with the other363* style constants (except PLAIN) for mixed styles.364*/365public static final int ITALIC = 2;366367/**368* The baseline used in most Roman scripts when laying out text.369*/370public static final int ROMAN_BASELINE = 0;371372/**373* The baseline used in ideographic scripts like Chinese, Japanese,374* and Korean when laying out text.375*/376public static final int CENTER_BASELINE = 1;377378/**379* The baseline used in Devanagari and similar scripts when laying380* out text.381*/382public static final int HANGING_BASELINE = 2;383384/**385* Identify a font resource of type TRUETYPE.386* Used to specify a TrueType font resource to the387* {@link #createFont} method.388* The TrueType format was extended to become the OpenType389* format, which adds support for fonts with Postscript outlines,390* this tag therefore references these fonts, as well as those391* with TrueType outlines.392* @since 1.3393*/394395public static final int TRUETYPE_FONT = 0;396397/**398* Identify a font resource of type TYPE1.399* Used to specify a Type1 font resource to the400* {@link #createFont} method.401* @since 1.5402*/403public static final int TYPE1_FONT = 1;404405/**406* The logical name of this {@code Font}, as passed to the407* constructor.408* @since 1.0409*410* @serial411* @see #getName412*/413protected String name;414415/**416* The style of this {@code Font}, as passed to the constructor.417* This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC.418* @since 1.0419*420* @serial421* @see #getStyle()422*/423protected int style;424425/**426* The point size of this {@code Font}, rounded to integer.427* @since 1.0428*429* @serial430* @see #getSize()431*/432protected int size;433434/**435* The point size of this {@code Font} in {@code float}.436*437* @serial438* @see #getSize()439* @see #getSize2D()440*/441protected float pointSize;442443/**444* The platform specific font information.445*/446private transient FontPeer peer;447private transient long pData; // native JDK1.1 font pointer448private transient Font2DHandle font2DHandle;449450private transient AttributeValues values;451private transient boolean hasLayoutAttributes;452453/*454* If the origin of a Font is a created font then this attribute455* must be set on all derived fonts too.456*/457private transient boolean createdFont = false;458459/*460* This is true if the font transform is not identity. It461* is used to avoid unnecessary instantiation of an AffineTransform.462*/463private transient boolean nonIdentityTx;464465/*466* A cached value used when a transform is required for internal467* use. This must not be exposed to callers since AffineTransform468* is mutable.469*/470private static final AffineTransform identityTx = new AffineTransform();471472/**473* Use serialVersionUID from JDK 1.1 for interoperability.474*/475@Serial476private static final long serialVersionUID = -4206021311591459213L;477478/**479* Gets the peer of this {@code Font}.480*481* @return the peer of the {@code Font}.482*/483private FontPeer getFontPeer() {484if(peer == null) {485Toolkit tk = Toolkit.getDefaultToolkit();486if (tk instanceof ComponentFactory) {487peer = ((ComponentFactory) tk).getFontPeer(name, style);488}489}490return peer;491}492493/**494* Return the AttributeValues object associated with this495* font. Most of the time, the internal object is null.496* If required, it will be created from the 'standard'497* state on the font. Only non-default values will be498* set in the AttributeValues object.499*500* <p>Since the AttributeValues object is mutable, and it501* is cached in the font, care must be taken to ensure that502* it is not mutated.503*/504private AttributeValues getAttributeValues() {505if (values == null) {506AttributeValues valuesTmp = new AttributeValues();507valuesTmp.setFamily(name);508valuesTmp.setSize(pointSize); // expects the float value.509510if ((style & BOLD) != 0) {511valuesTmp.setWeight(2); // WEIGHT_BOLD512}513514if ((style & ITALIC) != 0) {515valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE516}517valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility518values = valuesTmp;519}520521return values;522}523524private Font2D getFont2D() {525FontManager fm = FontManagerFactory.getInstance();526if (font2DHandle == null) {527font2DHandle =528fm.findFont2D(name, style,529FontManager.LOGICAL_FALLBACK).handle;530}531/* Do not cache the de-referenced font2D. It must be explicitly532* de-referenced to pick up a valid font in the event that the533* original one is marked invalid534*/535return font2DHandle.font2D;536}537538/**539* Creates a new {@code Font} from the specified name, style and540* point size.541* <p>542* The font name can be a font face name or a font family name.543* It is used together with the style to find an appropriate font face.544* When a font family name is specified, the style argument is used to545* select the most appropriate face from the family. When a font face546* name is specified, the face's style and the style argument are547* merged to locate the best matching font from the same family.548* For example if face name "Arial Bold" is specified with style549* {@code Font.ITALIC}, the font system looks for a face in the550* "Arial" family that is bold and italic, and may associate the font551* instance with the physical font face "Arial Bold Italic".552* The style argument is merged with the specified face's style, not553* added or subtracted.554* This means, specifying a bold face and a bold style does not555* double-embolden the font, and specifying a bold face and a plain556* style does not lighten the font.557* <p>558* If no face for the requested style can be found, the font system559* may apply algorithmic styling to achieve the desired style.560* For example, if {@code ITALIC} is requested, but no italic561* face is available, glyphs from the plain face may be algorithmically562* obliqued (slanted).563* <p>564* Font name lookup is case insensitive, using the case folding565* rules of the US locale.566* <p>567* If the {@code name} parameter represents something other than a568* logical font, i.e. is interpreted as a physical font face or family, and569* this cannot be mapped by the implementation to a physical font or a570* compatible alternative, then the font system will map the Font571* instance to "Dialog", such that for example, the family as reported572* by {@link #getFamily() getFamily} will be "Dialog".573*574* @param name the font name. This can be a font face name or a font575* family name, and may represent either a logical font or a physical576* font found in this {@code GraphicsEnvironment}.577* The family names for logical fonts are: Dialog, DialogInput,578* Monospaced, Serif, or SansSerif. Pre-defined String constants exist579* for all of these names, for example, {@code DIALOG}. If {@code name} is580* {@code null}, the <em>logical font name</em> of the new581* {@code Font} as returned by {@code getName()} is set to582* the name "Default".583* @param style the style constant for the {@code Font}584* The style argument is an integer bitmask that may585* be {@code PLAIN}, or a bitwise union of {@code BOLD} and/or586* {@code ITALIC} (for example, {@code ITALIC} or {@code BOLD|ITALIC}).587* If the style argument does not conform to one of the expected588* integer bitmasks then the style is set to {@code PLAIN}.589* @param size the point size of the {@code Font}590* @see GraphicsEnvironment#getAllFonts591* @see GraphicsEnvironment#getAvailableFontFamilyNames592* @since 1.0593*/594public Font(String name, int style, int size) {595this.name = (name != null) ? name : "Default";596this.style = (style & ~0x03) == 0 ? style : 0;597this.size = size;598this.pointSize = size;599}600601private Font(String name, int style, float sizePts) {602this.name = (name != null) ? name : "Default";603this.style = (style & ~0x03) == 0 ? style : 0;604this.size = (int)(sizePts + 0.5);605this.pointSize = sizePts;606}607608/* This constructor is used by deriveFont when attributes is null */609private Font(String name, int style, float sizePts,610boolean created, Font2DHandle handle) {611this(name, style, sizePts);612this.createdFont = created;613/* Fonts created from a stream will use the same font2D instance614* as the parent.615* One exception is that if the derived font is requested to be616* in a different style, then also check if its a CompositeFont617* and if so build a new CompositeFont from components of that style.618* CompositeFonts can only be marked as "created" if they are used619* to add fall backs to a physical font. And non-composites are620* always from "Font.createFont()" and shouldn't get this treatment.621*/622if (created) {623if (handle.font2D instanceof CompositeFont &&624handle.font2D.getStyle() != style) {625FontManager fm = FontManagerFactory.getInstance();626this.font2DHandle = fm.getNewComposite(null, style, handle);627} else {628this.font2DHandle = handle;629}630}631}632633/* used to implement Font.createFont */634private Font(File fontFile, int fontFormat,635boolean isCopy, CreatedFontTracker tracker)636throws FontFormatException {637this.createdFont = true;638/* Font2D instances created by this method track their font file639* so that when the Font2D is GC'd it can also remove the file.640*/641FontManager fm = FontManagerFactory.getInstance();642Font2D[] fonts =643fm.createFont2D(fontFile, fontFormat, false, isCopy, tracker);644this.font2DHandle = fonts[0].handle;645this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());646this.style = Font.PLAIN;647this.size = 1;648this.pointSize = 1f;649}650651/* This constructor is used when one font is derived from another.652* Fonts created from a stream will use the same font2D instance as the653* parent. They can be distinguished because the "created" argument654* will be "true". Since there is no way to recreate these fonts they655* need to have the handle to the underlying font2D passed in.656* "created" is also true when a special composite is referenced by the657* handle for essentially the same reasons.658* But when deriving a font in these cases two particular attributes659* need special attention: family/face and style.660* The "composites" in these cases need to be recreated with optimal661* fonts for the new values of family and style.662* For fonts created with createFont() these are treated differently.663* JDK can often synthesise a different style (bold from plain664* for example). For fonts created with "createFont" this is a reasonable665* solution but its also possible (although rare) to derive a font with a666* different family attribute. In this case JDK needs667* to break the tie with the original Font2D and find a new Font.668* The oldName and oldStyle are supplied so they can be compared with669* what the Font2D and the values. To speed things along :670* oldName == null will be interpreted as the name is unchanged.671* oldStyle = -1 will be interpreted as the style is unchanged.672* In these cases there is no need to interrogate "values".673*/674private Font(AttributeValues values, String oldName, int oldStyle,675boolean created, Font2DHandle handle) {676677this.createdFont = created;678if (created) {679this.font2DHandle = handle;680681String newName = null;682if (oldName != null) {683newName = values.getFamily();684if (oldName.equals(newName)) newName = null;685}686int newStyle = 0;687if (oldStyle == -1) {688newStyle = -1;689} else {690if (values.getWeight() >= 2f) newStyle = BOLD;691if (values.getPosture() >= .2f) newStyle |= ITALIC;692if (oldStyle == newStyle) newStyle = -1;693}694if (handle.font2D instanceof CompositeFont) {695if (newStyle != -1 || newName != null) {696FontManager fm = FontManagerFactory.getInstance();697this.font2DHandle =698fm.getNewComposite(newName, newStyle, handle);699}700} else if (newName != null) {701this.createdFont = false;702this.font2DHandle = null;703}704}705initFromValues(values);706}707708/**709* Creates a new {@code Font} with the specified attributes.710* Only keys defined in {@link java.awt.font.TextAttribute TextAttribute}711* are recognized. In addition the FONT attribute is712* not recognized by this constructor713* (see {@link #getAvailableAttributes}). Only attributes that have714* values of valid types will affect the new {@code Font}.715* <p>716* If {@code attributes} is {@code null}, a new717* {@code Font} is initialized with default values.718* @see java.awt.font.TextAttribute719* @param attributes the attributes to assign to the new720* {@code Font}, or {@code null}721*/722public Font(Map<? extends Attribute, ?> attributes) {723initFromValues(AttributeValues.fromMap(attributes, RECOGNIZED_MASK));724}725726/**727* Creates a new {@code Font} from the specified {@code font}.728* This constructor is intended for use by subclasses.729* @param font from which to create this {@code Font}.730* @throws NullPointerException if {@code font} is null731* @since 1.6732*/733protected Font(Font font) {734if (font.values != null) {735initFromValues(font.getAttributeValues().clone());736} else {737this.name = font.name;738this.style = font.style;739this.size = font.size;740this.pointSize = font.pointSize;741}742this.font2DHandle = font.font2DHandle;743this.createdFont = font.createdFont;744}745746/**747* Font recognizes all attributes except FONT.748*/749private static final int RECOGNIZED_MASK = AttributeValues.MASK_ALL750& ~AttributeValues.getMask(EFONT);751752/**753* These attributes are considered primary by the FONT attribute.754*/755private static final int PRIMARY_MASK =756AttributeValues.getMask(EFAMILY, EWEIGHT, EWIDTH, EPOSTURE, ESIZE,757ETRANSFORM, ESUPERSCRIPT, ETRACKING);758759/**760* These attributes are considered secondary by the FONT attribute.761*/762private static final int SECONDARY_MASK =763RECOGNIZED_MASK & ~PRIMARY_MASK;764765/**766* These attributes are handled by layout.767*/768private static final int LAYOUT_MASK =769AttributeValues.getMask(ECHAR_REPLACEMENT, EFOREGROUND, EBACKGROUND,770EUNDERLINE, ESTRIKETHROUGH, ERUN_DIRECTION,771EBIDI_EMBEDDING, EJUSTIFICATION,772EINPUT_METHOD_HIGHLIGHT, EINPUT_METHOD_UNDERLINE,773ESWAP_COLORS, ENUMERIC_SHAPING, EKERNING,774ELIGATURES, ETRACKING, ESUPERSCRIPT);775776private static final int EXTRA_MASK =777AttributeValues.getMask(ETRANSFORM, ESUPERSCRIPT, EWIDTH);778779/**780* Initialize the standard Font fields from the values object.781*/782private void initFromValues(AttributeValues values) {783this.values = values;784values.defineAll(PRIMARY_MASK); // for 1.5 streaming compatibility785786this.name = values.getFamily();787this.pointSize = values.getSize();788this.size = (int)(values.getSize() + 0.5);789if (values.getWeight() >= 2f) this.style |= BOLD; // not == 2f790if (values.getPosture() >= .2f) this.style |= ITALIC; // not == .2f791792this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK);793this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK);794}795796/**797* Returns true if any part of the specified text is from a798* complex script for which the implementation will need to invoke799* layout processing in order to render correctly when using800* {@link Graphics#drawString(String,int,int) drawString(String,int,int)}801* and other text rendering methods. Measurement of the text802* may similarly need the same extra processing.803* The {@code start} and {@code end} indices are provided so that804* the application can request only a subset of the text be considered.805* The last char index examined is at {@code "end-1"},806* i.e a request to examine the entire array would be807* <pre>808* {@code Font.textRequiresLayout(chars, 0, chars.length);}809* </pre>810* An application may find this information helpful in811* performance sensitive code.812* <p>813* Note that even if this method returns {@code false}, layout processing814* may still be invoked when used with any {@code Font}815* for which {@link #hasLayoutAttributes()} returns {@code true},816* so that method will need to be consulted for the specific font,817* in order to obtain an answer which accounts for such font attributes.818*819* @param chars the text.820* @param start the index of the first char to examine.821* @param end the ending index, exclusive.822* @return {@code true} if the specified text will need special layout.823* @throws NullPointerException if {@code chars} is null.824* @throws ArrayIndexOutOfBoundsException if {@code start} is negative or825* {@code end} is greater than the length of the {@code chars} array.826* @since 9827*/828public static boolean textRequiresLayout(char[] chars,829int start, int end) {830if (chars == null) {831throw new NullPointerException("null char array");832}833if (start < 0 || end > chars.length) {834throw new ArrayIndexOutOfBoundsException("start < 0 or end > len");835}836return FontUtilities.isComplexScript(chars, start, end);837}838839/**840* Returns a {@code Font} appropriate to the attributes.841* If {@code attributes} contains a {@code FONT} attribute842* with a valid {@code Font} as its value, it will be843* merged with any remaining attributes. See844* {@link java.awt.font.TextAttribute#FONT} for more845* information.846*847* @param attributes the attributes to assign to the new848* {@code Font}849* @return a new {@code Font} created with the specified850* attributes851* @throws NullPointerException if {@code attributes} is null.852* @since 1.2853* @see java.awt.font.TextAttribute854*/855public static Font getFont(Map<? extends Attribute, ?> attributes) {856// optimize for two cases:857// 1) FONT attribute, and nothing else858// 2) attributes, but no FONT859860// avoid turning the attributemap into a regular map for no reason861if (attributes instanceof AttributeMap &&862((AttributeMap)attributes).getValues() != null) {863AttributeValues values = ((AttributeMap)attributes).getValues();864if (values.isNonDefault(EFONT)) {865Font font = values.getFont();866if (!values.anyDefined(SECONDARY_MASK)) {867return font;868}869// merge870values = font.getAttributeValues().clone();871values.merge(attributes, SECONDARY_MASK);872return new Font(values, font.name, font.style,873font.createdFont, font.font2DHandle);874}875return new Font(attributes);876}877878Font font = (Font)attributes.get(TextAttribute.FONT);879if (font != null) {880if (attributes.size() > 1) { // oh well, check for anything else881AttributeValues values = font.getAttributeValues().clone();882values.merge(attributes, SECONDARY_MASK);883return new Font(values, font.name, font.style,884font.createdFont, font.font2DHandle);885}886887return font;888}889890return new Font(attributes);891}892893/**894* Used with the byte count tracker for fonts created from streams.895* If a thread can create temp files anyway, no point in counting896* font bytes.897*/898@SuppressWarnings("removal")899private static boolean hasTempPermission() {900901if (System.getSecurityManager() == null) {902return true;903}904File f = null;905boolean hasPerm = false;906try {907f = Files.createTempFile("+~JT", ".tmp").toFile();908f.delete();909f = null;910hasPerm = true;911} catch (Throwable t) {912/* inc. any kind of SecurityException */913}914return hasPerm;915}916917918/**919* Returns a new array of {@code Font} decoded from the specified stream.920* The returned {@code Font[]} will have at least one element.921* <p>922* The explicit purpose of this variation on the923* {@code createFont(int, InputStream)} method is to support font924* sources which represent a TrueType/OpenType font collection and925* be able to return all individual fonts in that collection.926* Consequently this method will throw {@code FontFormatException}927* if the data source does not contain at least one TrueType/OpenType928* font. The same exception will also be thrown if any of the fonts in929* the collection does not contain the required font tables.930* <p>931* The condition "at least one", allows for the stream to represent932* a single OpenType/TrueType font. That is, it does not have to be933* a collection.934* Each {@code Font} element of the returned array is935* created with a point size of 1 and style {@link #PLAIN PLAIN}.936* This base font can then be used with the {@code deriveFont}937* methods in this class to derive new {@code Font} objects with938* varying sizes, styles, transforms and font features.939* <p>This method does not close the {@link InputStream}.940* <p>941* To make each {@code Font} available to Font constructors it942* must be registered in the {@code GraphicsEnvironment} by calling943* {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.944* @param fontStream an {@code InputStream} object representing the945* input data for the font or font collection.946* @return a new {@code Font[]}.947* @throws FontFormatException if the {@code fontStream} data does948* not contain the required font tables for any of the elements of949* the collection, or if it contains no fonts at all.950* @throws IOException if the {@code fontStream} cannot be completely read.951* @see GraphicsEnvironment#registerFont(Font)952* @since 9953*/954public static Font[] createFonts(InputStream fontStream)955throws FontFormatException, IOException {956957final int fontFormat = Font.TRUETYPE_FONT;958if (hasTempPermission()) {959return createFont0(fontFormat, fontStream, true, null);960}961962// Otherwise, be extra conscious of pending temp file creation and963// resourcefully handle the temp file resources, among other things.964CreatedFontTracker tracker = CreatedFontTracker.getTracker();965boolean acquired = false;966try {967acquired = tracker.acquirePermit();968if (!acquired) {969throw new IOException("Timed out waiting for resources.");970}971return createFont0(fontFormat, fontStream, true, tracker);972} catch (InterruptedException e) {973throw new IOException("Problem reading font data.");974} finally {975if (acquired) {976tracker.releasePermit();977}978}979}980981/* used to implement Font.createFont */982private Font(Font2D font2D) {983984this.createdFont = true;985this.font2DHandle = font2D.handle;986this.name = font2D.getFontName(Locale.getDefault());987this.style = Font.PLAIN;988this.size = 1;989this.pointSize = 1f;990}991992/**993* Returns a new array of {@code Font} decoded from the specified file.994* The returned {@code Font[]} will have at least one element.995* <p>996* The explicit purpose of this variation on the997* {@code createFont(int, File)} method is to support font998* sources which represent a TrueType/OpenType font collection and999* be able to return all individual fonts in that collection.1000* Consequently this method will throw {@code FontFormatException}1001* if the data source does not contain at least one TrueType/OpenType1002* font. The same exception will also be thrown if any of the fonts in1003* the collection does not contain the required font tables.1004* <p>1005* The condition "at least one", allows for the stream to represent1006* a single OpenType/TrueType font. That is, it does not have to be1007* a collection.1008* Each {@code Font} element of the returned array is1009* created with a point size of 1 and style {@link #PLAIN PLAIN}.1010* This base font can then be used with the {@code deriveFont}1011* methods in this class to derive new {@code Font} objects with1012* varying sizes, styles, transforms and font features.1013* <p>1014* To make each {@code Font} available to Font constructors it1015* must be registered in the {@code GraphicsEnvironment} by calling1016* {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.1017* @param fontFile a {@code File} object containing the1018* input data for the font or font collection.1019* @return a new {@code Font[]}.1020* @throws FontFormatException if the {@code File} does1021* not contain the required font tables for any of the elements of1022* the collection, or if it contains no fonts at all.1023* @throws IOException if the {@code fontFile} cannot be read.1024* @see GraphicsEnvironment#registerFont(Font)1025* @since 91026*/1027public static Font[] createFonts(File fontFile)1028throws FontFormatException, IOException1029{1030int fontFormat = Font.TRUETYPE_FONT;1031fontFile = checkFontFile(fontFormat, fontFile);1032FontManager fm = FontManagerFactory.getInstance();1033Font2D[] font2DArr =1034fm.createFont2D(fontFile, fontFormat, true, false, null);1035int num = font2DArr.length;1036Font[] fonts = new Font[num];1037for (int i = 0; i < num; i++) {1038fonts[i] = new Font(font2DArr[i]);1039}1040return fonts;1041}10421043/**1044* Returns a new {@code Font} using the specified font type1045* and input data. The new {@code Font} is1046* created with a point size of 1 and style {@link #PLAIN PLAIN}.1047* This base font can then be used with the {@code deriveFont}1048* methods in this class to derive new {@code Font} objects with1049* varying sizes, styles, transforms and font features. This1050* method does not close the {@link InputStream}.1051* <p>1052* To make the {@code Font} available to Font constructors the1053* returned {@code Font} must be registered in the1054* {@code GraphicsEnvironment} by calling1055* {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.1056* @param fontFormat the type of the {@code Font}, which is1057* {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified.1058* or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified.1059* @param fontStream an {@code InputStream} object representing the1060* input data for the font.1061* @return a new {@code Font} created with the specified font type.1062* @throws IllegalArgumentException if {@code fontFormat} is not1063* {@code TRUETYPE_FONT} or {@code TYPE1_FONT}.1064* @throws FontFormatException if the {@code fontStream} data does1065* not contain the required font tables for the specified format.1066* @throws IOException if the {@code fontStream}1067* cannot be completely read.1068* @see GraphicsEnvironment#registerFont(Font)1069* @since 1.31070*/1071public static Font createFont(int fontFormat, InputStream fontStream)1072throws java.awt.FontFormatException, java.io.IOException {10731074if (hasTempPermission()) {1075return createFont0(fontFormat, fontStream, false, null)[0];1076}10771078// Otherwise, be extra conscious of pending temp file creation and1079// resourcefully handle the temp file resources, among other things.1080CreatedFontTracker tracker = CreatedFontTracker.getTracker();1081boolean acquired = false;1082try {1083acquired = tracker.acquirePermit();1084if (!acquired) {1085throw new IOException("Timed out waiting for resources.");1086}1087return createFont0(fontFormat, fontStream, false, tracker)[0];1088} catch (InterruptedException e) {1089throw new IOException("Problem reading font data.");1090} finally {1091if (acquired) {1092tracker.releasePermit();1093}1094}1095}10961097@SuppressWarnings("removal")1098private static Font[] createFont0(int fontFormat, InputStream fontStream,1099boolean allFonts,1100CreatedFontTracker tracker)1101throws java.awt.FontFormatException, java.io.IOException {11021103if (fontFormat != Font.TRUETYPE_FONT &&1104fontFormat != Font.TYPE1_FONT) {1105throw new IllegalArgumentException ("font format not recognized");1106}1107boolean copiedFontData = false;1108try {1109final File tFile = AccessController.doPrivileged(1110new PrivilegedExceptionAction<File>() {1111public File run() throws IOException {1112return Files.createTempFile("+~JF", ".tmp").toFile();1113}1114}1115);1116if (tracker != null) {1117tracker.add(tFile);1118}11191120int totalSize = 0;1121try {1122final OutputStream outStream =1123AccessController.doPrivileged(1124new PrivilegedExceptionAction<OutputStream>() {1125public OutputStream run() throws IOException {1126return new FileOutputStream(tFile);1127}1128}1129);1130if (tracker != null) {1131tracker.set(tFile, outStream);1132}1133try {1134byte[] buf = new byte[8192];1135for (;;) {1136int bytesRead = fontStream.read(buf);1137if (bytesRead < 0) {1138break;1139}1140if (tracker != null) {1141if (totalSize+bytesRead > CreatedFontTracker.MAX_FILE_SIZE) {1142throw new IOException("File too big.");1143}1144if (totalSize+tracker.getNumBytes() >1145CreatedFontTracker.MAX_TOTAL_BYTES)1146{1147throw new IOException("Total files too big.");1148}1149totalSize += bytesRead;1150tracker.addBytes(bytesRead);1151}1152outStream.write(buf, 0, bytesRead);1153}1154/* don't close the input stream */1155} finally {1156outStream.close();1157}1158/* After all references to a Font2D are dropped, the file1159* will be removed. To support long-lived AppContexts,1160* we need to then decrement the byte count by the size1161* of the file.1162* If the data isn't a valid font, the implementation will1163* delete the tmp file and decrement the byte count1164* in the tracker object before returning from the1165* constructor, so we can set 'copiedFontData' to true here1166* without waiting for the results of that constructor.1167*/1168copiedFontData = true;1169FontManager fm = FontManagerFactory.getInstance();1170Font2D[] font2DArr =1171fm.createFont2D(tFile, fontFormat, allFonts, true, tracker);1172int num = font2DArr.length;1173Font[] fonts = new Font[num];1174for (int i = 0; i < num; i++) {1175fonts[i] = new Font(font2DArr[i]);1176}1177return fonts;1178} finally {1179if (tracker != null) {1180tracker.remove(tFile);1181}1182if (!copiedFontData) {1183if (tracker != null) {1184tracker.subBytes(totalSize);1185}1186AccessController.doPrivileged(1187new PrivilegedExceptionAction<Void>() {1188public Void run() {1189tFile.delete();1190return null;1191}1192}1193);1194}1195}1196} catch (Throwable t) {1197if (t instanceof FontFormatException) {1198throw (FontFormatException)t;1199}1200if (t instanceof IOException) {1201throw (IOException)t;1202}1203Throwable cause = t.getCause();1204if (cause instanceof FontFormatException) {1205throw (FontFormatException)cause;1206}1207throw new IOException("Problem reading font data.");1208}1209}12101211/**1212* Returns a new {@code Font} using the specified font type1213* and the specified font file. The new {@code Font} is1214* created with a point size of 1 and style {@link #PLAIN PLAIN}.1215* This base font can then be used with the {@code deriveFont}1216* methods in this class to derive new {@code Font} objects with1217* varying sizes, styles, transforms and font features.1218* @param fontFormat the type of the {@code Font}, which is1219* {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is1220* specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is1221* specified.1222* So long as the returned font, or its derived fonts are referenced1223* the implementation may continue to access {@code fontFile}1224* to retrieve font data. Thus the results are undefined if the file1225* is changed, or becomes inaccessible.1226* <p>1227* To make the {@code Font} available to Font constructors the1228* returned {@code Font} must be registered in the1229* {@code GraphicsEnvironment} by calling1230* {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.1231* @param fontFile a {@code File} object representing the1232* input data for the font.1233* @return a new {@code Font} created with the specified font type.1234* @throws IllegalArgumentException if {@code fontFormat} is not1235* {@code TRUETYPE_FONT} or {@code TYPE1_FONT}.1236* @throws NullPointerException if {@code fontFile} is null.1237* @throws IOException if the {@code fontFile} cannot be read.1238* @throws FontFormatException if {@code fontFile} does1239* not contain the required font tables for the specified format.1240* @throws SecurityException if the executing code does not have1241* permission to read from the file.1242* @see GraphicsEnvironment#registerFont(Font)1243* @since 1.51244*/1245public static Font createFont(int fontFormat, File fontFile)1246throws java.awt.FontFormatException, java.io.IOException {12471248fontFile = checkFontFile(fontFormat, fontFile);1249return new Font(fontFile, fontFormat, false, null);1250}12511252private static File checkFontFile(int fontFormat, File fontFile)1253throws FontFormatException, IOException {12541255fontFile = new File(fontFile.getPath());12561257if (fontFormat != Font.TRUETYPE_FONT &&1258fontFormat != Font.TYPE1_FONT) {1259throw new IllegalArgumentException ("font format not recognized");1260}1261@SuppressWarnings("removal")1262SecurityManager sm = System.getSecurityManager();1263if (sm != null) {1264FilePermission filePermission =1265new FilePermission(fontFile.getPath(), "read");1266sm.checkPermission(filePermission);1267}1268if (!fontFile.canRead()) {1269throw new IOException("Can't read " + fontFile);1270}1271return fontFile;1272}12731274/**1275* Returns a copy of the transform associated with this1276* {@code Font}. This transform is not necessarily the one1277* used to construct the font. If the font has algorithmic1278* superscripting or width adjustment, this will be incorporated1279* into the returned {@code AffineTransform}.1280* <p>1281* Typically, fonts will not be transformed. Clients generally1282* should call {@link #isTransformed} first, and only call this1283* method if {@code isTransformed} returns true.1284*1285* @return an {@link AffineTransform} object representing the1286* transform attribute of this {@code Font} object.1287*/1288public AffineTransform getTransform() {1289/* The most common case is the identity transform. Most callers1290* should call isTransformed() first, to decide if they need to1291* get the transform, but some may not. Here we check to see1292* if we have a nonidentity transform, and only do the work to1293* fetch and/or compute it if so, otherwise we return a new1294* identity transform.1295*1296* Note that the transform is _not_ necessarily the same as1297* the transform passed in as an Attribute in a Map, as the1298* transform returned will also reflect the effects of WIDTH and1299* SUPERSCRIPT attributes. Clients who want the actual transform1300* need to call getRequestedAttributes.1301*/1302if (nonIdentityTx) {1303AttributeValues values = getAttributeValues();13041305AffineTransform at = values.isNonDefault(ETRANSFORM)1306? new AffineTransform(values.getTransform())1307: new AffineTransform();13081309if (values.getSuperscript() != 0) {1310// can't get ascent and descent here, recursive call to this fn,1311// so use pointsize1312// let users combine super- and sub-scripting13131314int superscript = values.getSuperscript();13151316double trans = 0;1317int n = 0;1318boolean up = superscript > 0;1319int sign = up ? -1 : 1;1320int ss = up ? superscript : -superscript;13211322while ((ss & 7) > n) {1323int newn = ss & 7;1324trans += sign * (ssinfo[newn] - ssinfo[n]);1325ss >>= 3;1326sign = -sign;1327n = newn;1328}1329trans *= pointSize;1330double scale = Math.pow(2./3., n);13311332at.preConcatenate(AffineTransform.getTranslateInstance(0, trans));1333at.scale(scale, scale);13341335// note on placement and italics1336// We preconcatenate the transform because we don't want to translate along1337// the italic angle, but purely perpendicular to the baseline. While this1338// looks ok for superscripts, it can lead subscripts to stack on each other1339// and bring the following text too close. The way we deal with potential1340// collisions that can occur in the case of italics is by adjusting the1341// horizontal spacing of the adjacent glyphvectors. Examine the italic1342// angle of both vectors, if one is non-zero, compute the minimum ascent1343// and descent, and then the x position at each for each vector along its1344// italic angle starting from its (offset) baseline. Compute the difference1345// between the x positions and use the maximum difference to adjust the1346// position of the right gv.1347}13481349if (values.isNonDefault(EWIDTH)) {1350at.scale(values.getWidth(), 1f);1351}13521353return at;1354}13551356return new AffineTransform();1357}13581359// x = r^0 + r^1 + r^2... r^n1360// rx = r^1 + r^2 + r^3... r^(n+1)1361// x - rx = r^0 - r^(n+1)1362// x (1 - r) = r^0 - r^(n+1)1363// x = (r^0 - r^(n+1)) / (1 - r)1364// x = (1 - r^(n+1)) / (1 - r)13651366// scale ratio is 2/31367// trans = 1/2 of ascent * x1368// assume ascent is 3/4 of point size13691370private static final float[] ssinfo = {13710.0f,13720.375f,13730.625f,13740.7916667f,13750.9027778f,13760.9768519f,13771.0262346f,13781.0591564f,1379};13801381/**1382* Returns the family name of this {@code Font}.1383*1384* <p>The family name of a font is font specific. Two fonts such as1385* Helvetica Italic and Helvetica Bold have the same family name,1386* <i>Helvetica</i>, whereas their font face names are1387* <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of1388* available family names may be obtained by using the1389* {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.1390*1391* <p>Use {@code getName} to get the logical name of the font.1392* Use {@code getFontName} to get the font face name of the font.1393* @return a {@code String} that is the family name of this1394* {@code Font}.1395*1396* @see #getName1397* @see #getFontName1398* @since 1.11399*/1400public String getFamily() {1401return getFamily_NoClientCode();1402}1403// NOTE: This method is called by privileged threads.1404// We implement this functionality in a package-private1405// method to insure that it cannot be overridden by client1406// subclasses.1407// DO NOT INVOKE CLIENT CODE ON THIS THREAD!1408final String getFamily_NoClientCode() {1409return getFamily(Locale.getDefault());1410}14111412/**1413* Returns the family name of this {@code Font}, localized for1414* the specified locale.1415*1416* <p>The family name of a font is font specific. Two fonts such as1417* Helvetica Italic and Helvetica Bold have the same family name,1418* <i>Helvetica</i>, whereas their font face names are1419* <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of1420* available family names may be obtained by using the1421* {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.1422*1423* <p>Use {@code getFontName} to get the font face name of the font.1424* @param l locale for which to get the family name1425* @return a {@code String} representing the family name of the1426* font, localized for the specified locale.1427* @see #getFontName1428* @see java.util.Locale1429* @since 1.21430*/1431public String getFamily(Locale l) {1432if (l == null) {1433throw new NullPointerException("null locale doesn't mean default");1434}1435return getFont2D().getFamilyName(l);1436}14371438/**1439* Returns the postscript name of this {@code Font}.1440* Use {@code getFamily} to get the family name of the font.1441* Use {@code getFontName} to get the font face name of the font.1442* @return a {@code String} representing the postscript name of1443* this {@code Font}.1444* @since 1.21445*/1446public String getPSName() {1447return getFont2D().getPostscriptName();1448}14491450/**1451* Returns the logical name of this {@code Font}.1452* Use {@code getFamily} to get the family name of the font.1453* Use {@code getFontName} to get the font face name of the font.1454* @return a {@code String} representing the logical name of1455* this {@code Font}.1456* @see #getFamily1457* @see #getFontName1458* @since 1.01459*/1460public String getName() {1461return name;1462}14631464/**1465* Returns the font face name of this {@code Font}. For example,1466* Helvetica Bold could be returned as a font face name.1467* Use {@code getFamily} to get the family name of the font.1468* Use {@code getName} to get the logical name of the font.1469* @return a {@code String} representing the font face name of1470* this {@code Font}.1471* @see #getFamily1472* @see #getName1473* @since 1.21474*/1475public String getFontName() {1476return getFontName(Locale.getDefault());1477}14781479/**1480* Returns the font face name of the {@code Font}, localized1481* for the specified locale. For example, Helvetica Fett could be1482* returned as the font face name.1483* Use {@code getFamily} to get the family name of the font.1484* @param l a locale for which to get the font face name1485* @return a {@code String} representing the font face name,1486* localized for the specified locale.1487* @see #getFamily1488* @see java.util.Locale1489*/1490public String getFontName(Locale l) {1491if (l == null) {1492throw new NullPointerException("null locale doesn't mean default");1493}1494return getFont2D().getFontName(l);1495}14961497/**1498* Returns the style of this {@code Font}. The style can be1499* PLAIN, BOLD, ITALIC, or BOLD+ITALIC.1500* @return the style of this {@code Font}1501* @see #isPlain1502* @see #isBold1503* @see #isItalic1504* @since 1.01505*/1506public int getStyle() {1507return style;1508}15091510/**1511* Returns the point size of this {@code Font}, rounded to1512* an integer.1513* Most users are familiar with the idea of using <i>point size</i> to1514* specify the size of glyphs in a font. This point size defines a1515* measurement between the baseline of one line to the baseline of the1516* following line in a single spaced text document. The point size is1517* based on <i>typographic points</i>, approximately 1/72 of an inch.1518* <p>1519* The Java(tm)2D API adopts the convention that one point is1520* equivalent to one unit in user coordinates. When using a1521* normalized transform for converting user space coordinates to1522* device space coordinates 72 user1523* space units equal 1 inch in device space. In this case one point1524* is 1/72 of an inch.1525* @return the point size of this {@code Font} in 1/72 of an1526* inch units.1527* @see #getSize2D1528* @see GraphicsConfiguration#getDefaultTransform1529* @see GraphicsConfiguration#getNormalizingTransform1530* @since 1.01531*/1532public int getSize() {1533return size;1534}15351536/**1537* Returns the point size of this {@code Font} in1538* {@code float} value.1539* @return the point size of this {@code Font} as a1540* {@code float} value.1541* @see #getSize1542* @since 1.21543*/1544public float getSize2D() {1545return pointSize;1546}15471548/**1549* Indicates whether or not this {@code Font} object's style is1550* PLAIN.1551* @return {@code true} if this {@code Font} has a1552* PLAIN style;1553* {@code false} otherwise.1554* @see java.awt.Font#getStyle1555* @since 1.01556*/1557public boolean isPlain() {1558return style == 0;1559}15601561/**1562* Indicates whether or not this {@code Font} object's style is1563* BOLD.1564* @return {@code true} if this {@code Font} object's1565* style is BOLD;1566* {@code false} otherwise.1567* @see java.awt.Font#getStyle1568* @since 1.01569*/1570public boolean isBold() {1571return (style & BOLD) != 0;1572}15731574/**1575* Indicates whether or not this {@code Font} object's style is1576* ITALIC.1577* @return {@code true} if this {@code Font} object's1578* style is ITALIC;1579* {@code false} otherwise.1580* @see java.awt.Font#getStyle1581* @since 1.01582*/1583public boolean isItalic() {1584return (style & ITALIC) != 0;1585}15861587/**1588* Indicates whether or not this {@code Font} object has a1589* transform that affects its size in addition to the Size1590* attribute.1591* @return {@code true} if this {@code Font} object1592* has a non-identity AffineTransform attribute.1593* {@code false} otherwise.1594* @see java.awt.Font#getTransform1595* @since 1.41596*/1597public boolean isTransformed() {1598return nonIdentityTx;1599}16001601/**1602* Return true if this Font contains attributes that require extra1603* layout processing.1604* @return true if the font has layout attributes1605* @since 1.61606*/1607public boolean hasLayoutAttributes() {1608return hasLayoutAttributes;1609}16101611/**1612* Returns a {@code Font} object from the system properties list.1613* {@code nm} is treated as the name of a system property to be1614* obtained. The {@code String} value of this property is then1615* interpreted as a {@code Font} object according to the1616* specification of {@code Font.decode(String)}1617* If the specified property is not found, or the executing code does1618* not have permission to read the property, null is returned instead.1619*1620* @param nm the property name1621* @return a {@code Font} object that the property name1622* describes, or null if no such property exists.1623* @throws NullPointerException if nm is null.1624* @since 1.21625* @see #decode(String)1626*/1627public static Font getFont(String nm) {1628return getFont(nm, null);1629}16301631/**1632* Returns the {@code Font} that the {@code str}1633* argument describes.1634* To ensure that this method returns the desired Font,1635* format the {@code str} parameter in1636* one of these ways1637*1638* <ul>1639* <li><em>fontname-style-pointsize</em>1640* <li><em>fontname-pointsize</em>1641* <li><em>fontname-style</em>1642* <li><em>fontname</em>1643* <li><em>fontname style pointsize</em>1644* <li><em>fontname pointsize</em>1645* <li><em>fontname style</em>1646* <li><em>fontname</em>1647* </ul>1648* in which <i>style</i> is one of the four1649* case-insensitive strings:1650* {@code "PLAIN"}, {@code "BOLD"}, {@code "BOLDITALIC"}, or1651* {@code "ITALIC"}, and pointsize is a positive decimal integer1652* representation of the point size.1653* For example, if you want a font that is Arial, bold, with1654* a point size of 18, you would call this method with:1655* "Arial-BOLD-18".1656* This is equivalent to calling the Font constructor :1657* {@code new Font("Arial", Font.BOLD, 18);}1658* and the values are interpreted as specified by that constructor.1659* <p>1660* A valid trailing decimal field is always interpreted as the pointsize.1661* Therefore a fontname containing a trailing decimal value should not1662* be used in the fontname only form.1663* <p>1664* If a style name field is not one of the valid style strings, it is1665* interpreted as part of the font name, and the default style is used.1666* <p>1667* Only one of ' ' or '-' may be used to separate fields in the input.1668* The identified separator is the one closest to the end of the string1669* which separates a valid pointsize, or a valid style name from1670* the rest of the string.1671* Null (empty) pointsize and style fields are treated1672* as valid fields with the default value for that field.1673*<p>1674* Some font names may include the separator characters ' ' or '-'.1675* If {@code str} is not formed with 3 components, e.g. such that1676* {@code style} or {@code pointsize} fields are not present in1677* {@code str}, and {@code fontname} also contains a1678* character determined to be the separator character1679* then these characters where they appear as intended to be part of1680* {@code fontname} may instead be interpreted as separators1681* so the font name may not be properly recognised.1682*1683* <p>1684* The default size is 12 and the default style is PLAIN.1685* If {@code str} does not specify a valid size, the returned1686* {@code Font} has a size of 12. If {@code str} does not1687* specify a valid style, the returned Font has a style of PLAIN.1688* If you do not specify a valid font name in1689* the {@code str} argument, this method will return1690* a font with the family name "Dialog".1691* To determine what font family names are available on1692* your system, use the1693* {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.1694* If {@code str} is {@code null}, a new {@code Font}1695* is returned with the family name "Dialog", a size of 12 and a1696* PLAIN style.1697* @param str the name of the font, or {@code null}1698* @return the {@code Font} object that {@code str}1699* describes, or a new default {@code Font} if1700* {@code str} is {@code null}.1701* @see #getFamily1702* @since 1.11703*/1704public static Font decode(String str) {1705String fontName = str;1706String styleName = "";1707int fontSize = 12;1708int fontStyle = Font.PLAIN;17091710if (str == null) {1711return new Font(DIALOG, fontStyle, fontSize);1712}17131714int lastHyphen = str.lastIndexOf('-');1715int lastSpace = str.lastIndexOf(' ');1716char sepChar = (lastHyphen > lastSpace) ? '-' : ' ';1717int sizeIndex = str.lastIndexOf(sepChar);1718int styleIndex = str.lastIndexOf(sepChar, sizeIndex-1);1719int strlen = str.length();17201721if (sizeIndex > 0 && sizeIndex+1 < strlen) {1722try {1723fontSize =1724Integer.valueOf(str.substring(sizeIndex+1)).intValue();1725if (fontSize <= 0) {1726fontSize = 12;1727}1728} catch (NumberFormatException e) {1729/* It wasn't a valid size, if we didn't also find the1730* start of the style string perhaps this is the style */1731styleIndex = sizeIndex;1732sizeIndex = strlen;1733if (str.charAt(sizeIndex-1) == sepChar) {1734sizeIndex--;1735}1736}1737}17381739if (styleIndex >= 0 && styleIndex+1 < strlen) {1740styleName = str.substring(styleIndex+1, sizeIndex);1741styleName = styleName.toLowerCase(Locale.ENGLISH);1742if (styleName.equals("bolditalic")) {1743fontStyle = Font.BOLD | Font.ITALIC;1744} else if (styleName.equals("italic")) {1745fontStyle = Font.ITALIC;1746} else if (styleName.equals("bold")) {1747fontStyle = Font.BOLD;1748} else if (styleName.equals("plain")) {1749fontStyle = Font.PLAIN;1750} else {1751/* this string isn't any of the expected styles, so1752* assume its part of the font name1753*/1754styleIndex = sizeIndex;1755if (str.charAt(styleIndex-1) == sepChar) {1756styleIndex--;1757}1758}1759fontName = str.substring(0, styleIndex);17601761} else {1762int fontEnd = strlen;1763if (styleIndex > 0) {1764fontEnd = styleIndex;1765} else if (sizeIndex > 0) {1766fontEnd = sizeIndex;1767}1768if (fontEnd > 0 && str.charAt(fontEnd-1) == sepChar) {1769fontEnd--;1770}1771fontName = str.substring(0, fontEnd);1772}17731774return new Font(fontName, fontStyle, fontSize);1775}17761777/**1778* Gets the specified {@code Font} from the system properties1779* list. As in the {@code getProperty} method of1780* {@code System}, the first1781* argument is treated as the name of a system property to be1782* obtained. The {@code String} value of this property is then1783* interpreted as a {@code Font} object.1784* <p>1785* The property value should be one of the forms accepted by1786* {@code Font.decode(String)}1787* If the specified property is not found, or the executing code does not1788* have permission to read the property, the {@code font}1789* argument is returned instead.1790* @param nm the case-insensitive property name1791* @param font a default {@code Font} to return if property1792* {@code nm} is not defined1793* @return the {@code Font} value of the property.1794* @throws NullPointerException if nm is null.1795* @see #decode(String)1796*/1797public static Font getFont(String nm, Font font) {1798String str = null;1799try {1800str =System.getProperty(nm);1801} catch(SecurityException e) {1802}1803if (str == null) {1804return font;1805}1806return decode ( str );1807}18081809transient int hash;1810/**1811* Returns a hashcode for this {@code Font}.1812* @return a hashcode value for this {@code Font}.1813* @since 1.01814*/1815public int hashCode() {1816if (hash == 0) {1817hash = name.hashCode() ^ style ^ size;1818/* It is possible many fonts differ only in transform.1819* So include the transform in the hash calculation.1820* nonIdentityTx is set whenever there is a transform in1821* 'values'. The tests for null are required because it can1822* also be set for other reasons.1823*/1824if (nonIdentityTx &&1825values != null && values.getTransform() != null) {1826hash ^= values.getTransform().hashCode();1827}1828}1829return hash;1830}18311832/**1833* Compares this {@code Font} object to the specified1834* {@code Object}.1835* @param obj the {@code Object} to compare1836* @return {@code true} if the objects are the same1837* or if the argument is a {@code Font} object1838* describing the same font as this object;1839* {@code false} otherwise.1840* @since 1.01841*/1842public boolean equals(Object obj) {1843if (obj == this) {1844return true;1845}18461847if (obj instanceof Font) {1848Font font = (Font)obj;1849if (size == font.size &&1850style == font.style &&1851nonIdentityTx == font.nonIdentityTx &&1852hasLayoutAttributes == font.hasLayoutAttributes &&1853pointSize == font.pointSize &&1854name.equals(font.name)) {18551856/* 'values' is usually initialized lazily, except when1857* the font is constructed from a Map, or derived using1858* a Map or other values. So if only one font has1859* the field initialized we need to initialize it in1860* the other instance and compare.1861*/1862if (values == null) {1863if (font.values == null) {1864return true;1865} else {1866return getAttributeValues().equals(font.values);1867}1868} else {1869return values.equals(font.getAttributeValues());1870}1871}1872}1873return false;1874}18751876/**1877* Converts this {@code Font} object to a {@code String}1878* representation.1879* @return a {@code String} representation of this1880* {@code Font} object.1881* @since 1.01882*/1883// NOTE: This method may be called by privileged threads.1884// DO NOT INVOKE CLIENT CODE ON THIS THREAD!1885public String toString() {1886String strStyle;18871888if (isBold()) {1889strStyle = isItalic() ? "bolditalic" : "bold";1890} else {1891strStyle = isItalic() ? "italic" : "plain";1892}18931894return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" +1895strStyle + ",size=" + size + "]";1896} // toString()189718981899/** Serialization support. A {@code readObject}1900* method is necessary because the constructor creates1901* the font's peer, and we can't serialize the peer.1902* Similarly the computed font "family" may be different1903* at {@code readObject} time than at1904* {@code writeObject} time. An integer version is1905* written so that future versions of this class will be1906* able to recognize serialized output from this one.1907*/1908/**1909* The {@code Font} Serializable Data Form.1910*1911* @serial1912*/1913private int fontSerializedDataVersion = 1;19141915/**1916* Writes default serializable fields to a stream.1917*1918* @param s the {@code ObjectOutputStream} to write1919* @throws IOException if an I/O error occurs1920* @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)1921* @see #readObject(java.io.ObjectInputStream)1922*/1923@Serial1924private void writeObject(java.io.ObjectOutputStream s)1925throws java.io.IOException1926{1927if (values != null) {1928synchronized(values) {1929// transient1930fRequestedAttributes = values.toSerializableHashtable();1931s.defaultWriteObject();1932fRequestedAttributes = null;1933}1934} else {1935s.defaultWriteObject();1936}1937}19381939/**1940* Reads the {@code ObjectInputStream}.1941* Unrecognized keys or values will be ignored.1942*1943* @param s the {@code ObjectInputStream} to read1944* @throws ClassNotFoundException if the class of a serialized object could1945* not be found1946* @throws IOException if an I/O error occurs1947* @serial1948* @see #writeObject(java.io.ObjectOutputStream)1949*/1950@Serial1951private void readObject(java.io.ObjectInputStream s)1952throws java.lang.ClassNotFoundException,1953java.io.IOException1954{1955s.defaultReadObject();1956if (pointSize == 0) {1957pointSize = (float)size;1958}19591960// Handle fRequestedAttributes.1961// in 1.5, we always streamed out the font values plus1962// TRANSFORM, SUPERSCRIPT, and WIDTH, regardless of whether the1963// values were default or not. In 1.6 we only stream out1964// defined values. So, 1.6 streams in from a 1.5 stream,1965// it check each of these values and 'undefines' it if the1966// value is the default.19671968if (fRequestedAttributes != null) {1969try {1970values = getAttributeValues(); // init1971AttributeValues extras =1972AttributeValues.fromSerializableHashtable(fRequestedAttributes);1973if (!AttributeValues.is16Hashtable(fRequestedAttributes)) {1974extras.unsetDefault(); // if legacy stream, undefine these1975}1976values = getAttributeValues().merge(extras);1977this.nonIdentityTx = values.anyNonDefault(EXTRA_MASK);1978this.hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK);1979} catch (Throwable t) {1980throw new IOException(t);1981} finally {1982fRequestedAttributes = null; // don't need it any more1983}1984}1985}19861987/**1988* Returns the number of glyphs in this {@code Font}. Glyph codes1989* for this {@code Font} range from 0 to1990* {@code getNumGlyphs()} - 1.1991* @return the number of glyphs in this {@code Font}.1992* @since 1.21993*/1994public int getNumGlyphs() {1995return getFont2D().getNumGlyphs();1996}19971998/**1999* Returns the glyphCode which is used when this {@code Font}2000* does not have a glyph for a specified unicode code point.2001* @return the glyphCode of this {@code Font}.2002* @since 1.22003*/2004public int getMissingGlyphCode() {2005return getFont2D().getMissingGlyphCode();2006}20072008/**2009* Returns the baseline appropriate for displaying this character.2010* <p>2011* Large fonts can support different writing systems, and each system can2012* use a different baseline.2013* The character argument determines the writing system to use. Clients2014* should not assume all characters use the same baseline.2015*2016* @param c a character used to identify the writing system2017* @return the baseline appropriate for the specified character.2018* @see LineMetrics#getBaselineOffsets2019* @see #ROMAN_BASELINE2020* @see #CENTER_BASELINE2021* @see #HANGING_BASELINE2022* @since 1.22023*/2024public byte getBaselineFor(char c) {2025return getFont2D().getBaselineFor(c);2026}20272028/**2029* Returns a map of font attributes available in this2030* {@code Font}. Attributes include things like ligatures and2031* glyph substitution.2032* @return the attributes map of this {@code Font}.2033*/2034public Map<TextAttribute,?> getAttributes(){2035return new AttributeMap(getAttributeValues());2036}20372038/**2039* Returns the keys of all the attributes supported by this2040* {@code Font}. These attributes can be used to derive other2041* fonts.2042* @return an array containing the keys of all the attributes2043* supported by this {@code Font}.2044* @since 1.22045*/2046public Attribute[] getAvailableAttributes() {2047// FONT is not supported by Font20482049Attribute[] attributes = {2050TextAttribute.FAMILY,2051TextAttribute.WEIGHT,2052TextAttribute.WIDTH,2053TextAttribute.POSTURE,2054TextAttribute.SIZE,2055TextAttribute.TRANSFORM,2056TextAttribute.SUPERSCRIPT,2057TextAttribute.CHAR_REPLACEMENT,2058TextAttribute.FOREGROUND,2059TextAttribute.BACKGROUND,2060TextAttribute.UNDERLINE,2061TextAttribute.STRIKETHROUGH,2062TextAttribute.RUN_DIRECTION,2063TextAttribute.BIDI_EMBEDDING,2064TextAttribute.JUSTIFICATION,2065TextAttribute.INPUT_METHOD_HIGHLIGHT,2066TextAttribute.INPUT_METHOD_UNDERLINE,2067TextAttribute.SWAP_COLORS,2068TextAttribute.NUMERIC_SHAPING,2069TextAttribute.KERNING,2070TextAttribute.LIGATURES,2071TextAttribute.TRACKING,2072};20732074return attributes;2075}20762077/**2078* Creates a new {@code Font} object by replicating this2079* {@code Font} object and applying a new style and size.2080* @param style the style for the new {@code Font}2081* @param size the size for the new {@code Font}2082* @return a new {@code Font} object.2083* @since 1.22084*/2085public Font deriveFont(int style, float size){2086if (values == null) {2087return new Font(name, style, size, createdFont, font2DHandle);2088}2089AttributeValues newValues = getAttributeValues().clone();2090int oldStyle = (this.style != style) ? this.style : -1;2091applyStyle(style, newValues);2092newValues.setSize(size);2093return new Font(newValues, null, oldStyle, createdFont, font2DHandle);2094}20952096/**2097* Creates a new {@code Font} object by replicating this2098* {@code Font} object and applying a new style and transform.2099* @param style the style for the new {@code Font}2100* @param trans the {@code AffineTransform} associated with the2101* new {@code Font}2102* @return a new {@code Font} object.2103* @throws IllegalArgumentException if {@code trans} is2104* {@code null}2105* @since 1.22106*/2107public Font deriveFont(int style, AffineTransform trans){2108AttributeValues newValues = getAttributeValues().clone();2109int oldStyle = (this.style != style) ? this.style : -1;2110applyStyle(style, newValues);2111applyTransform(trans, newValues);2112return new Font(newValues, null, oldStyle, createdFont, font2DHandle);2113}21142115/**2116* Creates a new {@code Font} object by replicating the current2117* {@code Font} object and applying a new size to it.2118* @param size the size for the new {@code Font}.2119* @return a new {@code Font} object.2120* @since 1.22121*/2122public Font deriveFont(float size){2123if (values == null) {2124return new Font(name, style, size, createdFont, font2DHandle);2125}2126AttributeValues newValues = getAttributeValues().clone();2127newValues.setSize(size);2128return new Font(newValues, null, -1, createdFont, font2DHandle);2129}21302131/**2132* Creates a new {@code Font} object by replicating the current2133* {@code Font} object and applying a new transform to it.2134* @param trans the {@code AffineTransform} associated with the2135* new {@code Font}2136* @return a new {@code Font} object.2137* @throws IllegalArgumentException if {@code trans} is2138* {@code null}2139* @since 1.22140*/2141public Font deriveFont(AffineTransform trans){2142AttributeValues newValues = getAttributeValues().clone();2143applyTransform(trans, newValues);2144return new Font(newValues, null, -1, createdFont, font2DHandle);2145}21462147/**2148* Creates a new {@code Font} object by replicating the current2149* {@code Font} object and applying a new style to it.2150* @param style the style for the new {@code Font}2151* @return a new {@code Font} object.2152* @since 1.22153*/2154public Font deriveFont(int style){2155if (values == null) {2156return new Font(name, style, size, createdFont, font2DHandle);2157}2158AttributeValues newValues = getAttributeValues().clone();2159int oldStyle = (this.style != style) ? this.style : -1;2160applyStyle(style, newValues);2161return new Font(newValues, null, oldStyle, createdFont, font2DHandle);2162}21632164/**2165* Creates a new {@code Font} object by replicating the current2166* {@code Font} object and applying a new set of font attributes2167* to it.2168*2169* @param attributes a map of attributes enabled for the new2170* {@code Font}2171* @return a new {@code Font} object.2172* @since 1.22173*/2174public Font deriveFont(Map<? extends Attribute, ?> attributes) {2175if (attributes == null) {2176return this;2177}2178AttributeValues newValues = getAttributeValues().clone();2179newValues.merge(attributes, RECOGNIZED_MASK);21802181return new Font(newValues, name, style, createdFont, font2DHandle);2182}21832184/**2185* Checks if this {@code Font} has a glyph for the specified2186* character.2187*2188* <p> <b>Note:</b> This method cannot handle2189* <a href="../../../java.base/java/lang/Character.html#supplementary">2190* supplementary characters</a>.2191* To support all Unicode characters, including2192* supplementary characters, use the {@link #canDisplay(int)}2193* method or {@code canDisplayUpTo} methods.2194*2195* @param c the character for which a glyph is needed2196* @return {@code true} if this {@code Font} has a glyph for this2197* character; {@code false} otherwise.2198* @since 1.22199*/2200public boolean canDisplay(char c){2201return getFont2D().canDisplay(c);2202}22032204/**2205* Checks if this {@code Font} has a glyph for the specified2206* character.2207*2208* @param codePoint the character (Unicode code point) for which a glyph2209* is needed.2210* @return {@code true} if this {@code Font} has a glyph for the2211* character; {@code false} otherwise.2212* @throws IllegalArgumentException if the code point is not a valid Unicode2213* code point.2214* @see Character#isValidCodePoint(int)2215* @since 1.52216*/2217public boolean canDisplay(int codePoint) {2218if (!Character.isValidCodePoint(codePoint)) {2219throw new IllegalArgumentException("invalid code point: " +2220Integer.toHexString(codePoint));2221}2222return getFont2D().canDisplay(codePoint);2223}22242225/**2226* Indicates whether or not this {@code Font} can display a2227* specified {@code String}. For strings with Unicode encoding,2228* it is important to know if a particular font can display the2229* string. This method returns an offset into the {@code String}2230* {@code str} which is the first character this2231* {@code Font} cannot display without using the missing glyph2232* code. If the {@code Font} can display all characters, -1 is2233* returned.2234* @param str a {@code String} object2235* @return an offset into {@code str} that points2236* to the first character in {@code str} that this2237* {@code Font} cannot display; or {@code -1} if2238* this {@code Font} can display all characters in2239* {@code str}.2240* @since 1.22241*/2242public int canDisplayUpTo(String str) {2243Font2D font2d = getFont2D();2244int len = str.length();2245for (int i = 0; i < len; i++) {2246char c = str.charAt(i);2247if (font2d.canDisplay(c)) {2248continue;2249}2250if (!Character.isHighSurrogate(c)) {2251return i;2252}2253if (!font2d.canDisplay(str.codePointAt(i))) {2254return i;2255}2256i++;2257}2258return -1;2259}22602261/**2262* Indicates whether or not this {@code Font} can display2263* the characters in the specified {@code text}2264* starting at {@code start} and ending at2265* {@code limit}. This method is a convenience overload.2266* @param text the specified array of {@code char} values2267* @param start the specified starting offset (in2268* {@code char}s) into the specified array of2269* {@code char} values2270* @param limit the specified ending offset (in2271* {@code char}s) into the specified array of2272* {@code char} values2273* @return an offset into {@code text} that points2274* to the first character in {@code text} that this2275* {@code Font} cannot display; or {@code -1} if2276* this {@code Font} can display all characters in2277* {@code text}.2278* @since 1.22279*/2280public int canDisplayUpTo(char[] text, int start, int limit) {2281Font2D font2d = getFont2D();2282for (int i = start; i < limit; i++) {2283char c = text[i];2284if (font2d.canDisplay(c)) {2285continue;2286}2287if (!Character.isHighSurrogate(c)) {2288return i;2289}2290if (!font2d.canDisplay(Character.codePointAt(text, i, limit))) {2291return i;2292}2293i++;2294}2295return -1;2296}22972298/**2299* Indicates whether or not this {@code Font} can display the2300* text specified by the {@code iter} starting at2301* {@code start} and ending at {@code limit}.2302*2303* @param iter a {@link CharacterIterator} object2304* @param start the specified starting offset into the specified2305* {@code CharacterIterator}.2306* @param limit the specified ending offset into the specified2307* {@code CharacterIterator}.2308* @return an offset into {@code iter} that points2309* to the first character in {@code iter} that this2310* {@code Font} cannot display; or {@code -1} if2311* this {@code Font} can display all characters in2312* {@code iter}.2313* @since 1.22314*/2315public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {2316Font2D font2d = getFont2D();2317char c = iter.setIndex(start);2318for (int i = start; i < limit; i++, c = iter.next()) {2319if (font2d.canDisplay(c)) {2320continue;2321}2322if (!Character.isHighSurrogate(c)) {2323return i;2324}2325char c2 = iter.next();2326// c2 could be CharacterIterator.DONE which is not a low surrogate.2327if (!Character.isLowSurrogate(c2)) {2328return i;2329}2330if (!font2d.canDisplay(Character.toCodePoint(c, c2))) {2331return i;2332}2333i++;2334}2335return -1;2336}23372338/**2339* Returns the italic angle of this {@code Font}. The italic angle2340* is the inverse slope of the caret which best matches the posture of this2341* {@code Font}.2342* @see TextAttribute#POSTURE2343* @return the angle of the ITALIC style of this {@code Font}.2344*/2345public float getItalicAngle() {2346return getItalicAngle(null);2347}23482349/* The FRC hints don't affect the value of the italic angle but2350* we need to pass them in to look up a strike.2351* If we can pass in ones already being used it can prevent an extra2352* strike from being allocated. Note that since italic angle is2353* a property of the font, the font transform is needed not the2354* device transform. Finally, this is private but the only caller of this2355* in the JDK - and the only likely caller - is in this same class.2356*/2357private float getItalicAngle(FontRenderContext frc) {2358Object aa, fm;2359if (frc == null) {2360aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;2361fm = RenderingHints.VALUE_FRACTIONALMETRICS_OFF;2362} else {2363aa = frc.getAntiAliasingHint();2364fm = frc.getFractionalMetricsHint();2365}2366return getFont2D().getItalicAngle(this, identityTx, aa, fm);2367}23682369/**2370* Checks whether or not this {@code Font} has uniform2371* line metrics. A logical {@code Font} might be a2372* composite font, which means that it is composed of different2373* physical fonts to cover different code ranges. Each of these2374* fonts might have different {@code LineMetrics}. If the2375* logical {@code Font} is a single2376* font then the metrics would be uniform.2377* @return {@code true} if this {@code Font} has2378* uniform line metrics; {@code false} otherwise.2379*/2380public boolean hasUniformLineMetrics() {2381return false; // REMIND always safe, but prevents caller optimize2382}23832384private transient SoftReference<FontLineMetrics> flmref;2385private FontLineMetrics defaultLineMetrics(FontRenderContext frc) {2386FontLineMetrics flm = null;2387if (flmref == null2388|| (flm = flmref.get()) == null2389|| !flm.frc.equals(frc)) {23902391/* The device transform in the frc is not used in obtaining line2392* metrics, although it probably should be: REMIND find why not?2393* The font transform is used but its applied in getFontMetrics, so2394* just pass identity here2395*/2396float [] metrics = new float[8];2397getFont2D().getFontMetrics(this, identityTx,2398frc.getAntiAliasingHint(),2399frc.getFractionalMetricsHint(),2400metrics);2401float ascent = metrics[0];2402float descent = metrics[1];2403float leading = metrics[2];2404float ssOffset = 0;2405if (values != null && values.getSuperscript() != 0) {2406ssOffset = (float)getTransform().getTranslateY();2407ascent -= ssOffset;2408descent += ssOffset;2409}2410float height = ascent + descent + leading;24112412int baselineIndex = 0; // need real index, assumes roman for everything2413// need real baselines eventually2414float[] baselineOffsets = { 0, (descent/2f - ascent) / 2f, -ascent };24152416float strikethroughOffset = metrics[4];2417float strikethroughThickness = metrics[5];24182419float underlineOffset = metrics[6];2420float underlineThickness = metrics[7];24212422float italicAngle = getItalicAngle(frc);24232424if (isTransformed()) {2425AffineTransform ctx = values.getCharTransform(); // extract rotation2426if (ctx != null) {2427Point2D.Float pt = new Point2D.Float();2428pt.setLocation(0, strikethroughOffset);2429ctx.deltaTransform(pt, pt);2430strikethroughOffset = pt.y;2431pt.setLocation(0, strikethroughThickness);2432ctx.deltaTransform(pt, pt);2433strikethroughThickness = pt.y;2434pt.setLocation(0, underlineOffset);2435ctx.deltaTransform(pt, pt);2436underlineOffset = pt.y;2437pt.setLocation(0, underlineThickness);2438ctx.deltaTransform(pt, pt);2439underlineThickness = pt.y;2440}2441}2442strikethroughOffset += ssOffset;2443underlineOffset += ssOffset;24442445CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height,2446baselineIndex, baselineOffsets,2447strikethroughOffset, strikethroughThickness,2448underlineOffset, underlineThickness,2449ssOffset, italicAngle);24502451flm = new FontLineMetrics(0, cm, frc);2452flmref = new SoftReference<FontLineMetrics>(flm);2453}24542455return (FontLineMetrics)flm.clone();2456}24572458/**2459* Returns a {@link LineMetrics} object created with the specified2460* {@code String} and {@link FontRenderContext}.2461* @param str the specified {@code String}2462* @param frc the specified {@code FontRenderContext}2463* @return a {@code LineMetrics} object created with the2464* specified {@code String} and {@link FontRenderContext}.2465*/2466public LineMetrics getLineMetrics( String str, FontRenderContext frc) {2467FontLineMetrics flm = defaultLineMetrics(frc);2468flm.numchars = str.length();2469return flm;2470}24712472/**2473* Returns a {@code LineMetrics} object created with the2474* specified arguments.2475* @param str the specified {@code String}2476* @param beginIndex the initial offset of {@code str}2477* @param limit the end offset of {@code str}2478* @param frc the specified {@code FontRenderContext}2479* @return a {@code LineMetrics} object created with the2480* specified arguments.2481*/2482public LineMetrics getLineMetrics( String str,2483int beginIndex, int limit,2484FontRenderContext frc) {2485FontLineMetrics flm = defaultLineMetrics(frc);2486int numChars = limit - beginIndex;2487flm.numchars = (numChars < 0)? 0: numChars;2488return flm;2489}24902491/**2492* Returns a {@code LineMetrics} object created with the2493* specified arguments.2494* @param chars an array of characters2495* @param beginIndex the initial offset of {@code chars}2496* @param limit the end offset of {@code chars}2497* @param frc the specified {@code FontRenderContext}2498* @return a {@code LineMetrics} object created with the2499* specified arguments.2500*/2501public LineMetrics getLineMetrics(char [] chars,2502int beginIndex, int limit,2503FontRenderContext frc) {2504FontLineMetrics flm = defaultLineMetrics(frc);2505int numChars = limit - beginIndex;2506flm.numchars = (numChars < 0)? 0: numChars;2507return flm;2508}25092510/**2511* Returns a {@code LineMetrics} object created with the2512* specified arguments.2513* @param ci the specified {@code CharacterIterator}2514* @param beginIndex the initial offset in {@code ci}2515* @param limit the end offset of {@code ci}2516* @param frc the specified {@code FontRenderContext}2517* @return a {@code LineMetrics} object created with the2518* specified arguments.2519*/2520public LineMetrics getLineMetrics(CharacterIterator ci,2521int beginIndex, int limit,2522FontRenderContext frc) {2523FontLineMetrics flm = defaultLineMetrics(frc);2524int numChars = limit - beginIndex;2525flm.numchars = (numChars < 0)? 0: numChars;2526return flm;2527}25282529/**2530* Returns the logical bounds of the specified {@code String} in2531* the specified {@code FontRenderContext}. The logical bounds2532* contains the origin, ascent, advance, and height, which includes2533* the leading. The logical bounds does not always enclose all the2534* text. For example, in some languages and in some fonts, accent2535* marks can be positioned above the ascent or below the descent.2536* To obtain a visual bounding box, which encloses all the text,2537* use the {@link TextLayout#getBounds() getBounds} method of2538* {@code TextLayout}.2539* <p>Note: The returned bounds is in baseline-relative coordinates2540* (see {@link java.awt.Font class notes}).2541* @param str the specified {@code String}2542* @param frc the specified {@code FontRenderContext}2543* @return a {@link Rectangle2D} that is the bounding box of the2544* specified {@code String} in the specified2545* {@code FontRenderContext}.2546* @see FontRenderContext2547* @see Font#createGlyphVector2548* @since 1.22549*/2550public Rectangle2D getStringBounds( String str, FontRenderContext frc) {2551char[] array = str.toCharArray();2552return getStringBounds(array, 0, array.length, frc);2553}25542555/**2556* Returns the logical bounds of the specified {@code String} in2557* the specified {@code FontRenderContext}. The logical bounds2558* contains the origin, ascent, advance, and height, which includes2559* the leading. The logical bounds does not always enclose all the2560* text. For example, in some languages and in some fonts, accent2561* marks can be positioned above the ascent or below the descent.2562* To obtain a visual bounding box, which encloses all the text,2563* use the {@link TextLayout#getBounds() getBounds} method of2564* {@code TextLayout}.2565* <p>Note: The returned bounds is in baseline-relative coordinates2566* (see {@link java.awt.Font class notes}).2567* @param str the specified {@code String}2568* @param beginIndex the initial offset of {@code str}2569* @param limit the end offset of {@code str}2570* @param frc the specified {@code FontRenderContext}2571* @return a {@code Rectangle2D} that is the bounding box of the2572* specified {@code String} in the specified2573* {@code FontRenderContext}.2574* @throws IndexOutOfBoundsException if {@code beginIndex} is2575* less than zero, or {@code limit} is greater than the2576* length of {@code str}, or {@code beginIndex}2577* is greater than {@code limit}.2578* @see FontRenderContext2579* @see Font#createGlyphVector2580* @since 1.22581*/2582public Rectangle2D getStringBounds( String str,2583int beginIndex, int limit,2584FontRenderContext frc) {2585String substr = str.substring(beginIndex, limit);2586return getStringBounds(substr, frc);2587}25882589/**2590* Returns the logical bounds of the specified array of characters2591* in the specified {@code FontRenderContext}. The logical2592* bounds contains the origin, ascent, advance, and height, which2593* includes the leading. The logical bounds does not always enclose2594* all the text. For example, in some languages and in some fonts,2595* accent marks can be positioned above the ascent or below the2596* descent. To obtain a visual bounding box, which encloses all the2597* text, use the {@link TextLayout#getBounds() getBounds} method of2598* {@code TextLayout}.2599* <p>Note: The returned bounds is in baseline-relative coordinates2600* (see {@link java.awt.Font class notes}).2601* @param chars an array of characters2602* @param beginIndex the initial offset in the array of2603* characters2604* @param limit the end offset in the array of characters2605* @param frc the specified {@code FontRenderContext}2606* @return a {@code Rectangle2D} that is the bounding box of the2607* specified array of characters in the specified2608* {@code FontRenderContext}.2609* @throws IndexOutOfBoundsException if {@code beginIndex} is2610* less than zero, or {@code limit} is greater than the2611* length of {@code chars}, or {@code beginIndex}2612* is greater than {@code limit}.2613* @see FontRenderContext2614* @see Font#createGlyphVector2615* @since 1.22616*/2617public Rectangle2D getStringBounds(char [] chars,2618int beginIndex, int limit,2619FontRenderContext frc) {2620if (beginIndex < 0) {2621throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);2622}2623if (limit > chars.length) {2624throw new IndexOutOfBoundsException("limit: " + limit);2625}2626if (beginIndex > limit) {2627throw new IndexOutOfBoundsException("range length: " +2628(limit - beginIndex));2629}26302631// this code should be in textlayout2632// quick check for simple text, assume GV ok to use if simple26332634boolean simple = values == null ||2635(values.getKerning() == 0 && values.getLigatures() == 0 &&2636values.getBaselineTransform() == null);2637if (simple) {2638simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);2639}26402641if (simple || ((limit - beginIndex) == 0)) {2642FontDesignMetrics metrics = FontDesignMetrics.getMetrics(this, frc);2643return metrics.getSimpleBounds(chars, beginIndex, limit-beginIndex);2644} else {2645// need char array constructor on textlayout2646String str = new String(chars, beginIndex, limit - beginIndex);2647TextLayout tl = new TextLayout(str, this, frc);2648return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),2649tl.getAscent() + tl.getDescent() +2650tl.getLeading());2651}2652}26532654/**2655* Returns the logical bounds of the characters indexed in the2656* specified {@link CharacterIterator} in the2657* specified {@code FontRenderContext}. The logical bounds2658* contains the origin, ascent, advance, and height, which includes2659* the leading. The logical bounds does not always enclose all the2660* text. For example, in some languages and in some fonts, accent2661* marks can be positioned above the ascent or below the descent.2662* To obtain a visual bounding box, which encloses all the text,2663* use the {@link TextLayout#getBounds() getBounds} method of2664* {@code TextLayout}.2665* <p>Note: The returned bounds is in baseline-relative coordinates2666* (see {@link java.awt.Font class notes}).2667* @param ci the specified {@code CharacterIterator}2668* @param beginIndex the initial offset in {@code ci}2669* @param limit the end offset in {@code ci}2670* @param frc the specified {@code FontRenderContext}2671* @return a {@code Rectangle2D} that is the bounding box of the2672* characters indexed in the specified {@code CharacterIterator}2673* in the specified {@code FontRenderContext}.2674* @see FontRenderContext2675* @see Font#createGlyphVector2676* @since 1.22677* @throws IndexOutOfBoundsException if {@code beginIndex} is2678* less than the start index of {@code ci}, or2679* {@code limit} is greater than the end index of2680* {@code ci}, or {@code beginIndex} is greater2681* than {@code limit}2682*/2683public Rectangle2D getStringBounds(CharacterIterator ci,2684int beginIndex, int limit,2685FontRenderContext frc) {2686int start = ci.getBeginIndex();2687int end = ci.getEndIndex();26882689if (beginIndex < start) {2690throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);2691}2692if (limit > end) {2693throw new IndexOutOfBoundsException("limit: " + limit);2694}2695if (beginIndex > limit) {2696throw new IndexOutOfBoundsException("range length: " +2697(limit - beginIndex));2698}26992700char[] arr = new char[limit - beginIndex];27012702ci.setIndex(beginIndex);2703for(int idx = 0; idx < arr.length; idx++) {2704arr[idx] = ci.current();2705ci.next();2706}27072708return getStringBounds(arr,0,arr.length,frc);2709}27102711/**2712* Returns the bounds for the character with the maximum2713* bounds as defined in the specified {@code FontRenderContext}.2714* <p>Note: The returned bounds is in baseline-relative coordinates2715* (see {@link java.awt.Font class notes}).2716* @param frc the specified {@code FontRenderContext}2717* @return a {@code Rectangle2D} that is the bounding box2718* for the character with the maximum bounds.2719*/2720public Rectangle2D getMaxCharBounds(FontRenderContext frc) {2721float [] metrics = new float[4];27222723getFont2D().getFontMetrics(this, frc, metrics);27242725return new Rectangle2D.Float(0, -metrics[0],2726metrics[3],2727metrics[0] + metrics[1] + metrics[2]);2728}27292730/**2731* Creates a {@link java.awt.font.GlyphVector GlyphVector} by2732* mapping characters to glyphs one-to-one based on the2733* Unicode cmap in this {@code Font}. This method does no other2734* processing besides the mapping of glyphs to characters. This2735* means that this method is not useful for some scripts, such2736* as Arabic, Hebrew, Thai, and Indic, that require reordering,2737* shaping, or ligature substitution.2738* @param frc the specified {@code FontRenderContext}2739* @param str the specified {@code String}2740* @return a new {@code GlyphVector} created with the2741* specified {@code String} and the specified2742* {@code FontRenderContext}.2743*/2744public GlyphVector createGlyphVector(FontRenderContext frc, String str)2745{2746return (GlyphVector)new StandardGlyphVector(this, str, frc);2747}27482749/**2750* Creates a {@link java.awt.font.GlyphVector GlyphVector} by2751* mapping characters to glyphs one-to-one based on the2752* Unicode cmap in this {@code Font}. This method does no other2753* processing besides the mapping of glyphs to characters. This2754* means that this method is not useful for some scripts, such2755* as Arabic, Hebrew, Thai, and Indic, that require reordering,2756* shaping, or ligature substitution.2757* @param frc the specified {@code FontRenderContext}2758* @param chars the specified array of characters2759* @return a new {@code GlyphVector} created with the2760* specified array of characters and the specified2761* {@code FontRenderContext}.2762*/2763public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars)2764{2765return (GlyphVector)new StandardGlyphVector(this, chars, frc);2766}27672768/**2769* Creates a {@link java.awt.font.GlyphVector GlyphVector} by2770* mapping the specified characters to glyphs one-to-one based on the2771* Unicode cmap in this {@code Font}. This method does no other2772* processing besides the mapping of glyphs to characters. This2773* means that this method is not useful for some scripts, such2774* as Arabic, Hebrew, Thai, and Indic, that require reordering,2775* shaping, or ligature substitution.2776* @param frc the specified {@code FontRenderContext}2777* @param ci the specified {@code CharacterIterator}2778* @return a new {@code GlyphVector} created with the2779* specified {@code CharacterIterator} and the specified2780* {@code FontRenderContext}.2781*/2782public GlyphVector createGlyphVector( FontRenderContext frc,2783CharacterIterator ci)2784{2785return (GlyphVector)new StandardGlyphVector(this, ci, frc);2786}27872788/**2789* Creates a {@link java.awt.font.GlyphVector GlyphVector} by2790* mapping characters to glyphs one-to-one based on the2791* Unicode cmap in this {@code Font}. This method does no other2792* processing besides the mapping of glyphs to characters. This2793* means that this method is not useful for some scripts, such2794* as Arabic, Hebrew, Thai, and Indic, that require reordering,2795* shaping, or ligature substitution.2796* @param frc the specified {@code FontRenderContext}2797* @param glyphCodes the specified integer array2798* @return a new {@code GlyphVector} created with the2799* specified integer array and the specified2800* {@code FontRenderContext}.2801*/2802public GlyphVector createGlyphVector( FontRenderContext frc,2803int [] glyphCodes)2804{2805return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc);2806}28072808/**2809* Returns a new {@code GlyphVector} object, performing full2810* layout of the text if possible. Full layout is required for2811* complex text, such as Arabic or Hindi. Support for different2812* scripts depends on the font and implementation.2813* <p>2814* Layout requires bidi analysis, as performed by2815* {@code Bidi}, and should only be performed on text that2816* has a uniform direction. The direction is indicated in the2817* flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a2818* right-to-left (Arabic and Hebrew) run direction, or2819* LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English)2820* run direction.2821* <p>2822* In addition, some operations, such as Arabic shaping, require2823* context, so that the characters at the start and limit can have2824* the proper shapes. Sometimes the data in the buffer outside2825* the provided range does not have valid data. The values2826* LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be2827* added to the flags parameter to indicate that the text before2828* start, or after limit, respectively, should not be examined2829* for context.2830* <p>2831* All other values for the flags parameter are reserved.2832*2833* @param frc the specified {@code FontRenderContext}2834* @param text the text to layout2835* @param start the start of the text to use for the {@code GlyphVector}2836* @param limit the limit of the text to use for the {@code GlyphVector}2837* @param flags control flags as described above2838* @return a new {@code GlyphVector} representing the text between2839* start and limit, with glyphs chosen and positioned so as to best represent2840* the text2841* @throws ArrayIndexOutOfBoundsException if start or limit is2842* out of bounds2843* @see java.text.Bidi2844* @see #LAYOUT_LEFT_TO_RIGHT2845* @see #LAYOUT_RIGHT_TO_LEFT2846* @see #LAYOUT_NO_START_CONTEXT2847* @see #LAYOUT_NO_LIMIT_CONTEXT2848* @since 1.42849*/2850public GlyphVector layoutGlyphVector(FontRenderContext frc,2851char[] text,2852int start,2853int limit,2854int flags) {28552856GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines2857StandardGlyphVector gv = gl.layout(this, frc, text,2858start, limit-start, flags, null);2859GlyphLayout.done(gl);2860return gv;2861}28622863/**2864* A flag to layoutGlyphVector indicating that text is left-to-right as2865* determined by Bidi analysis.2866*/2867public static final int LAYOUT_LEFT_TO_RIGHT = 0;28682869/**2870* A flag to layoutGlyphVector indicating that text is right-to-left as2871* determined by Bidi analysis.2872*/2873public static final int LAYOUT_RIGHT_TO_LEFT = 1;28742875/**2876* A flag to layoutGlyphVector indicating that text in the char array2877* before the indicated start should not be examined.2878*/2879public static final int LAYOUT_NO_START_CONTEXT = 2;28802881/**2882* A flag to layoutGlyphVector indicating that text in the char array2883* after the indicated limit should not be examined.2884*/2885public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;288628872888private static void applyTransform(AffineTransform trans, AttributeValues values) {2889if (trans == null) {2890throw new IllegalArgumentException("transform must not be null");2891}2892values.setTransform(trans);2893}28942895private static void applyStyle(int style, AttributeValues values) {2896// WEIGHT_BOLD, WEIGHT_REGULAR2897values.setWeight((style & BOLD) != 0 ? 2f : 1f);2898// POSTURE_OBLIQUE, POSTURE_REGULAR2899values.setPosture((style & ITALIC) != 0 ? .2f : 0f);2900}29012902/*2903* Initialize JNI field and method IDs2904*/2905private static native void initIDs();2906}290729082909