0001: /*
0002: * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package java.awt;
0027:
0028: import java.awt.font.FontRenderContext;
0029: import java.awt.font.GlyphVector;
0030: import java.awt.font.LineMetrics;
0031: import java.awt.font.TextAttribute;
0032: import java.awt.font.TextLayout;
0033: import java.awt.font.TransformAttribute;
0034: import java.awt.geom.AffineTransform;
0035: import java.awt.geom.Point2D;
0036: import java.awt.geom.Rectangle2D;
0037: import java.awt.peer.FontPeer;
0038: import java.io.*;
0039: import java.lang.ref.SoftReference;
0040: import java.text.AttributedCharacterIterator.Attribute;
0041: import java.text.CharacterIterator;
0042: import java.text.StringCharacterIterator;
0043: import java.util.HashMap;
0044: import java.util.Hashtable;
0045: import java.util.Locale;
0046: import java.util.Map;
0047: import sun.font.StandardGlyphVector;
0048: import sun.java2d.FontSupport;
0049:
0050: import sun.font.AttributeMap;
0051: import sun.font.AttributeValues;
0052: import sun.font.EAttribute;
0053: import sun.font.CompositeFont;
0054: import sun.font.Font2D;
0055: import sun.font.Font2DHandle;
0056: import sun.font.FontManager;
0057: import sun.font.GlyphLayout;
0058: import sun.font.FontLineMetrics;
0059: import sun.font.CoreMetrics;
0060:
0061: import static sun.font.EAttribute.*;
0062:
0063: /**
0064: * The <code>Font</code> class represents fonts, which are used to
0065: * render text in a visible way.
0066: * A font provides the information needed to map sequences of
0067: * <em>characters</em> to sequences of <em>glyphs</em>
0068: * and to render sequences of glyphs on <code>Graphics</code> and
0069: * <code>Component</code> objects.
0070: *
0071: * <h4>Characters and Glyphs</h4>
0072: *
0073: * A <em>character</em> is a symbol that represents an item such as a letter,
0074: * a digit, or punctuation in an abstract way. For example, <code>'g'</code>,
0075: * <font size=-1>LATIN SMALL LETTER G</font>, is a character.
0076: * <p>
0077: * A <em>glyph</em> is a shape used to render a character or a sequence of
0078: * characters. In simple writing systems, such as Latin, typically one glyph
0079: * represents one character. In general, however, characters and glyphs do not
0080: * have one-to-one correspondence. For example, the character 'á'
0081: * <font size=-1>LATIN SMALL LETTER A WITH ACUTE</font>, can be represented by
0082: * two glyphs: one for 'a' and one for '´'. On the other hand, the
0083: * two-character string "fi" can be represented by a single glyph, an
0084: * "fi" ligature. In complex writing systems, such as Arabic or the South
0085: * and South-East Asian writing systems, the relationship between characters
0086: * and glyphs can be more complicated and involve context-dependent selection
0087: * of glyphs as well as glyph reordering.
0088: *
0089: * A font encapsulates the collection of glyphs needed to render a selected set
0090: * of characters as well as the tables needed to map sequences of characters to
0091: * corresponding sequences of glyphs.
0092: *
0093: * <h4>Physical and Logical Fonts</h4>
0094: *
0095: * The Java Platform distinguishes between two kinds of fonts:
0096: * <em>physical</em> fonts and <em>logical</em> fonts.
0097: * <p>
0098: * <em>Physical</em> fonts are the actual font libraries containing glyph data
0099: * and tables to map from character sequences to glyph sequences, using a font
0100: * technology such as TrueType or PostScript Type 1.
0101: * All implementations of the Java Platform must support TrueType fonts;
0102: * support for other font technologies is implementation dependent.
0103: * Physical fonts may use names such as Helvetica, Palatino, HonMincho, or
0104: * any number of other font names.
0105: * Typically, each physical font supports only a limited set of writing
0106: * systems, for example, only Latin characters or only Japanese and Basic
0107: * Latin.
0108: * The set of available physical fonts varies between configurations.
0109: * Applications that require specific fonts can bundle them and instantiate
0110: * them using the {@link #createFont createFont} method.
0111: * <p>
0112: * <em>Logical</em> fonts are the five font families defined by the Java
0113: * platform which must be supported by any Java runtime environment:
0114: * Serif, SansSerif, Monospaced, Dialog, and DialogInput.
0115: * These logical fonts are not actual font libraries. Instead, the logical
0116: * font names are mapped to physical fonts by the Java runtime environment.
0117: * The mapping is implementation and usually locale dependent, so the look
0118: * and the metrics provided by them vary.
0119: * Typically, each logical font name maps to several physical fonts in order to
0120: * cover a large range of characters.
0121: * <p>
0122: * Peered AWT components, such as {@link Label Label} and
0123: * {@link TextField TextField}, can only use logical fonts.
0124: * <p>
0125: * For a discussion of the relative advantages and disadvantages of using
0126: * physical or logical fonts, see the
0127: * <a href="http://java.sun.com/j2se/corejava/intl/reference/faqs/index.html#desktop-rendering">Internationalization FAQ</a>
0128: * document.
0129: *
0130: * <h4>Font Faces and Names</h4>
0131: *
0132: * A <code>Font</code>
0133: * can have many faces, such as heavy, medium, oblique, gothic and
0134: * regular. All of these faces have similar typographic design.
0135: * <p>
0136: * There are three different names that you can get from a
0137: * <code>Font</code> object. The <em>logical font name</em> is simply the
0138: * name that was used to construct the font.
0139: * The <em>font face name</em>, or just <em>font name</em> for
0140: * short, is the name of a particular font face, like Helvetica Bold. The
0141: * <em>family name</em> is the name of the font family that determines the
0142: * typographic design across several faces, like Helvetica.
0143: * <p>
0144: * The <code>Font</code> class represents an instance of a font face from
0145: * a collection of font faces that are present in the system resources
0146: * of the host system. As examples, Arial Bold and Courier Bold Italic
0147: * are font faces. There can be several <code>Font</code> objects
0148: * associated with a font face, each differing in size, style, transform
0149: * and font features.
0150: * <p>
0151: * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method
0152: * of the <code>GraphicsEnvironment</code> class returns an
0153: * array of all font faces available in the system. These font faces are
0154: * returned as <code>Font</code> objects with a size of 1, identity
0155: * transform and default font features. These
0156: * base fonts can then be used to derive new <code>Font</code> objects
0157: * with varying sizes, styles, transforms and font features via the
0158: * <code>deriveFont</code> methods in this class.
0159: *
0160: * <h4>Font and TextAttribute</h4>
0161: *
0162: * <p><code>Font</code> supports most
0163: * <code>TextAttribute</code>s. This makes some operations, such as
0164: * rendering underlined text, convenient since it is not
0165: * necessary to explicitly construct a <code>TextLayout</code> object.
0166: * Attributes can be set on a Font by constructing or deriving it
0167: * using a <code>Map</code> of <code>TextAttribute</code> values.
0168: *
0169: * <p>The values of some <code>TextAttributes</code> are not
0170: * serializable, and therefore attempting to serialize an instance of
0171: * <code>Font</code> that has such values will not serialize them.
0172: * This means a Font deserialized from such a stream will not compare
0173: * equal to the original Font that contained the non-serializable
0174: * attributes. This should very rarely pose a problem
0175: * since these attributes are typically used only in special
0176: * circumstances and are unlikely to be serialized.
0177: *
0178: * <ul>
0179: * <li><code>FOREGROUND</code> and <code>BACKGROUND</code> use
0180: * <code>Paint</code> values. The subclass <code>Color</code> is
0181: * serializable, while <code>GradientPaint</code> and
0182: * <code>TexturePaint</code> are not.</li>
0183: * <li><code>CHAR_REPLACEMENT</code> uses
0184: * <code>GraphicAttribute</code> values. The subclasses
0185: * <code>ShapeGraphicAttribute</code> and
0186: * <code>ImageGraphicAttribute</code> are not serializable.</li>
0187: * <li><code>INPUT_METHOD_HIGHLIGHT</code> uses
0188: * <code>InputMethodHighlight</code> values, which are
0189: * not serializable. See {@link java.awt.im.InputMethodHighlight}.</li>
0190: * </ul>
0191: *
0192: * Clients who create custom subclasses of <code>Paint</code> and
0193: * <code>GraphicAttribute</code> can make them serializable and
0194: * avoid this problem. Clients who use input method highlights can
0195: * convert these to the platform-specific attributes for that
0196: * highlight on the current platform and set them on the Font as
0197: * a workaround.</p>
0198: *
0199: * <p>The <code>Map</code>-based constructor and
0200: * <code>deriveFont</code> APIs ignore the FONT attribute, and it is
0201: * not retained by the Font; the static {@link #getFont} method should
0202: * be used if the FONT attribute might be present. See {@link
0203: * java.awt.font.TextAttribute#FONT} for more information.</p>
0204: *
0205: * <p>Several attributes will cause additional rendering overhead
0206: * and potentially invoke layout. If a <code>Font</code> has such
0207: * attributes, the <code>{@link #hasLayoutAttributes()}</code> method
0208: * will return true.</p>
0209: *
0210: * <p>Note: Font rotations can cause text baselines to be rotated. In
0211: * order to account for this (rare) possibility, font APIs are
0212: * specified to return metrics and take parameters 'in
0213: * baseline-relative coordinates'. This maps the 'x' coordinate to
0214: * the advance along the baseline, (positive x is forward along the
0215: * baseline), and the 'y' coordinate to a distance along the
0216: * perpendicular to the baseline at 'x' (positive y is 90 degrees
0217: * clockwise from the baseline vector). APIs for which this is
0218: * especially important are called out as having 'baseline-relative
0219: * coordinates.'
0220: */
0221: public class Font implements java.io.Serializable {
0222: static {
0223: /* ensure that the necessary native libraries are loaded */
0224: Toolkit.loadLibraries();
0225: initIDs();
0226: }
0227:
0228: /**
0229: * This is now only used during serialization. Typically
0230: * it is null.
0231: *
0232: * @serial
0233: * @see #getAttributes()
0234: */
0235: private Hashtable fRequestedAttributes;
0236:
0237: /*
0238: * Constants to be used for logical font family names.
0239: */
0240:
0241: /**
0242: * A String constant for the canonical family name of the
0243: * logical font "Dialog". It is useful in Font construction
0244: * to provide compile-time verification of the name.
0245: * @since 1.6
0246: */
0247: public static final String DIALOG = "Dialog";
0248:
0249: /**
0250: * A String constant for the canonical family name of the
0251: * logical font "DialogInput". It is useful in Font construction
0252: * to provide compile-time verification of the name.
0253: * @since 1.6
0254: */
0255: public static final String DIALOG_INPUT = "DialogInput";
0256:
0257: /**
0258: * A String constant for the canonical family name of the
0259: * logical font "SansSerif". It is useful in Font construction
0260: * to provide compile-time verification of the name.
0261: * @since 1.6
0262: */
0263: public static final String SANS_SERIF = "SansSerif";
0264:
0265: /**
0266: * A String constant for the canonical family name of the
0267: * logical font "Serif". It is useful in Font construction
0268: * to provide compile-time verification of the name.
0269: * @since 1.6
0270: */
0271: public static final String SERIF = "Serif";
0272:
0273: /**
0274: * A String constant for the canonical family name of the
0275: * logical font "Monospaced". It is useful in Font construction
0276: * to provide compile-time verification of the name.
0277: * @since 1.6
0278: */
0279: public static final String MONOSPACED = "Monospaced";
0280:
0281: /*
0282: * Constants to be used for styles. Can be combined to mix
0283: * styles.
0284: */
0285:
0286: /**
0287: * The plain style constant.
0288: */
0289: public static final int PLAIN = 0;
0290:
0291: /**
0292: * The bold style constant. This can be combined with the other style
0293: * constants (except PLAIN) for mixed styles.
0294: */
0295: public static final int BOLD = 1;
0296:
0297: /**
0298: * The italicized style constant. This can be combined with the other
0299: * style constants (except PLAIN) for mixed styles.
0300: */
0301: public static final int ITALIC = 2;
0302:
0303: /**
0304: * The baseline used in most Roman scripts when laying out text.
0305: */
0306: public static final int ROMAN_BASELINE = 0;
0307:
0308: /**
0309: * The baseline used in ideographic scripts like Chinese, Japanese,
0310: * and Korean when laying out text.
0311: */
0312: public static final int CENTER_BASELINE = 1;
0313:
0314: /**
0315: * The baseline used in Devanigiri and similar scripts when laying
0316: * out text.
0317: */
0318: public static final int HANGING_BASELINE = 2;
0319:
0320: /**
0321: * Identify a font resource of type TRUETYPE.
0322: * Used to specify a TrueType font resource to the
0323: * {@link #createFont} method.
0324: * @since 1.3
0325: */
0326:
0327: public static final int TRUETYPE_FONT = 0;
0328:
0329: /**
0330: * Identify a font resource of type TYPE1.
0331: * Used to specify a Type1 font resource to the
0332: * {@link #createFont} method.
0333: * @since 1.5
0334: */
0335: public static final int TYPE1_FONT = 1;
0336:
0337: /**
0338: * The logical name of this <code>Font</code>, as passed to the
0339: * constructor.
0340: * @since JDK1.0
0341: *
0342: * @serial
0343: * @see #getName
0344: */
0345: protected String name;
0346:
0347: /**
0348: * The style of this <code>Font</code>, as passed to the constructor.
0349: * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
0350: * @since JDK1.0
0351: *
0352: * @serial
0353: * @see #getStyle()
0354: */
0355: protected int style;
0356:
0357: /**
0358: * The point size of this <code>Font</code>, rounded to integer.
0359: * @since JDK1.0
0360: *
0361: * @serial
0362: * @see #getSize()
0363: */
0364: protected int size;
0365:
0366: /**
0367: * The point size of this <code>Font</code> in <code>float</code>.
0368: *
0369: * @serial
0370: * @see #getSize()
0371: * @see #getSize2D()
0372: */
0373: protected float pointSize;
0374:
0375: /**
0376: * The platform specific font information.
0377: */
0378: private transient FontPeer peer;
0379: private transient long pData; // native JDK1.1 font pointer
0380: private transient Font2DHandle font2DHandle;
0381:
0382: private transient AttributeValues values;
0383: private transient boolean hasLayoutAttributes;
0384:
0385: /*
0386: * If the origin of a Font is a created font then this attribute
0387: * must be set on all derived fonts too.
0388: */
0389: private transient boolean createdFont = false;
0390:
0391: /*
0392: * This is true if the font transform is not identity. It
0393: * is used to avoid unnecessary instantiation of an AffineTransform.
0394: */
0395: private transient boolean nonIdentityTx;
0396:
0397: /*
0398: * A cached value used when a transform is required for internal
0399: * use. This must not be exposed to callers since AffineTransform
0400: * is mutable.
0401: */
0402: private static final AffineTransform identityTx = new AffineTransform();
0403:
0404: /*
0405: * JDK 1.1 serialVersionUID
0406: */
0407: private static final long serialVersionUID = -4206021311591459213L;
0408:
0409: /**
0410: * Gets the peer of this <code>Font</code>.
0411: * @return the peer of the <code>Font</code>.
0412: * @since JDK1.1
0413: * @deprecated Font rendering is now platform independent.
0414: */
0415: @Deprecated
0416: public FontPeer getPeer() {
0417: return getPeer_NoClientCode();
0418: }
0419:
0420: // NOTE: This method is called by privileged threads.
0421: // We implement this functionality in a package-private method
0422: // to insure that it cannot be overridden by client subclasses.
0423: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
0424: final FontPeer getPeer_NoClientCode() {
0425: if (peer == null) {
0426: Toolkit tk = Toolkit.getDefaultToolkit();
0427: this .peer = tk.getFontPeer(name, style);
0428: }
0429: return peer;
0430: }
0431:
0432: /**
0433: * Return the AttributeValues object associated with this
0434: * font. Most of the time, the internal object is null.
0435: * If required, it will be created from the 'standard'
0436: * state on the font. Only non-default values will be
0437: * set in the AttributeValues object.
0438: *
0439: * <p>Since the AttributeValues object is mutable, and it
0440: * is cached in the font, care must be taken to ensure that
0441: * it is not mutated.
0442: */
0443: private AttributeValues getAttributeValues() {
0444: if (values == null) {
0445: values = new AttributeValues();
0446: values.setFamily(name);
0447: values.setSize(pointSize); // expects the float value.
0448:
0449: if ((style & BOLD) != 0) {
0450: values.setWeight(2); // WEIGHT_BOLD
0451: }
0452:
0453: if ((style & ITALIC) != 0) {
0454: values.setPosture(.2f); // POSTURE_OBLIQUE
0455: }
0456: values.defineAll(PRIMARY_MASK); // for streaming compatibility
0457: }
0458:
0459: return values;
0460: }
0461:
0462: private Font2D getFont2D() {
0463: if (FontManager.usingPerAppContextComposites
0464: && font2DHandle != null
0465: && font2DHandle.font2D instanceof CompositeFont
0466: && ((CompositeFont) (font2DHandle.font2D))
0467: .isStdComposite()) {
0468: return FontManager.findFont2D(name, style,
0469: FontManager.LOGICAL_FALLBACK);
0470: } else if (font2DHandle == null) {
0471: font2DHandle = FontManager.findFont2D(name, style,
0472: FontManager.LOGICAL_FALLBACK).handle;
0473: }
0474: /* Do not cache the de-referenced font2D. It must be explicitly
0475: * de-referenced to pick up a valid font in the event that the
0476: * original one is marked invalid
0477: */
0478: return font2DHandle.font2D;
0479: }
0480:
0481: /**
0482: * Creates a new <code>Font</code> from the specified name, style and
0483: * point size.
0484: * <p>
0485: * The font name can be a font face name or a font family name.
0486: * It is used together with the style to find an appropriate font face.
0487: * When a font family name is specified, the style argument is used to
0488: * select the most appropriate face from the family. When a font face
0489: * name is specified, the face's style and the style argument are
0490: * merged to locate the best matching font from the same family.
0491: * For example if face name "Arial Bold" is specified with style
0492: * <code>Font.ITALIC</code>, the font system looks for a face in the
0493: * "Arial" family that is bold and italic, and may associate the font
0494: * instance with the physical font face "Arial Bold Italic".
0495: * The style argument is merged with the specified face's style, not
0496: * added or subtracted.
0497: * This means, specifying a bold face and a bold style does not
0498: * double-embolden the font, and specifying a bold face and a plain
0499: * style does not lighten the font.
0500: * <p>
0501: * If no face for the requested style can be found, the font system
0502: * may apply algorithmic styling to achieve the desired style.
0503: * For example, if <code>ITALIC</code> is requested, but no italic
0504: * face is available, glyphs from the plain face may be algorithmically
0505: * obliqued (slanted).
0506: * <p>
0507: * Font name lookup is case insensitive, using the case folding
0508: * rules of the US locale.
0509: * <p>
0510: * If the <code>name</code> parameter represents something other than a
0511: * logical font, i.e. is interpreted as a physical font face or family, and
0512: * this cannot be mapped by the implementation to a physical font or a
0513: * compatible alternative, then the font system will map the Font
0514: * instance to "Dialog", such that for example, the family as reported
0515: * by {@link #getFamily() getFamily} will be "Dialog".
0516: * <p>
0517: *
0518: * @param name the font name. This can be a font face name or a font
0519: * family name, and may represent either a logical font or a physical
0520: * font found in this {@code GraphicsEnvironment}.
0521: * The family names for logical fonts are: Dialog, DialogInput,
0522: * Monospaced, Serif, or SansSerif. Pre-defined String constants exist
0523: * for all of these names, for example, {@code DIALOG}. If {@code name} is
0524: * {@code null}, the <em>logical font name</em> of the new
0525: * {@code Font} as returned by {@code getName()} is set to
0526: * the name "Default".
0527: * @param style the style constant for the {@code Font}
0528: * The style argument is an integer bitmask that may
0529: * be {@code PLAIN}, or a bitwise union of {@code BOLD} and/or
0530: * {@code ITALIC} (for example, {@code ITALIC} or {@code BOLD|ITALIC}).
0531: * If the style argument does not conform to one of the expected
0532: * integer bitmasks then the style is set to {@code PLAIN}.
0533: * @param size the point size of the {@code Font}
0534: * @see GraphicsEnvironment#getAllFonts
0535: * @see GraphicsEnvironment#getAvailableFontFamilyNames
0536: * @since JDK1.0
0537: */
0538: public Font(String name, int style, int size) {
0539: this .name = (name != null) ? name : "Default";
0540: this .style = (style & ~0x03) == 0 ? style : 0;
0541: this .size = size;
0542: this .pointSize = size;
0543: }
0544:
0545: private Font(String name, int style, float sizePts) {
0546: this .name = (name != null) ? name : "Default";
0547: this .style = (style & ~0x03) == 0 ? style : 0;
0548: this .size = (int) (sizePts + 0.5);
0549: this .pointSize = sizePts;
0550: }
0551:
0552: /* This constructor is used by deriveFont when attributes is null */
0553: private Font(String name, int style, float sizePts,
0554: boolean created, Font2DHandle handle) {
0555: this (name, style, sizePts);
0556: this .createdFont = created;
0557: /* Fonts created from a stream will use the same font2D instance
0558: * as the parent.
0559: * One exception is that if the derived font is requested to be
0560: * in a different style, then also check if its a CompositeFont
0561: * and if so build a new CompositeFont from components of that style.
0562: * CompositeFonts can only be marked as "created" if they are used
0563: * to add fall backs to a physical font. And non-composites are
0564: * always from "Font.createFont()" and shouldn't get this treatment.
0565: */
0566: if (created) {
0567: if (handle.font2D instanceof CompositeFont
0568: && handle.font2D.getStyle() != style) {
0569: this .font2DHandle = FontManager.getNewComposite(null,
0570: style, handle);
0571: } else {
0572: this .font2DHandle = handle;
0573: }
0574: }
0575: }
0576:
0577: /* used to implement Font.createFont */
0578: private Font(File fontFile, int fontFormat, boolean isCopy)
0579: throws FontFormatException {
0580: this .createdFont = true;
0581: /* Font2D instances created by this method track their font file
0582: * so that when the Font2D is GC'd it can also remove the file.
0583: */
0584: this .font2DHandle = FontManager.createFont2D(fontFile,
0585: fontFormat, isCopy).handle;
0586: this .name = this .font2DHandle.font2D.getFontName(Locale
0587: .getDefault());
0588: this .style = Font.PLAIN;
0589: this .size = 1;
0590: this .pointSize = 1f;
0591: }
0592:
0593: /* This constructor is used when one font is derived from another.
0594: * Fonts created from a stream will use the same font2D instance as the
0595: * parent. They can be distinguished because the "created" argument
0596: * will be "true". Since there is no way to recreate these fonts they
0597: * need to have the handle to the underlying font2D passed in.
0598: * "created" is also true when a special composite is referenced by the
0599: * handle for essentially the same reasons.
0600: * But when deriving a font in these cases two particular attributes
0601: * need special attention: family/face and style.
0602: * The "composites" in these cases need to be recreated with optimal
0603: * fonts for the new values of family and style.
0604: * For fonts created with createFont() these are treated differently.
0605: * JDK can often synthesise a different style (bold from plain
0606: * for example). For fonts created with "createFont" this is a reasonable
0607: * solution but its also possible (although rare) to derive a font with a
0608: * different family attribute. In this case JDK needs
0609: * to break the tie with the original Font2D and find a new Font.
0610: * The oldName and oldStyle are supplied so they can be compared with
0611: * what the Font2D and the values. To speed things along :
0612: * oldName == null will be interpreted as the name is unchanged.
0613: * oldStyle = -1 will be interpreted as the style is unchanged.
0614: * In these cases there is no need to interrogate "values".
0615: */
0616: private Font(AttributeValues values, String oldName, int oldStyle,
0617: boolean created, Font2DHandle handle) {
0618:
0619: this .createdFont = created;
0620: if (created) {
0621: this .font2DHandle = handle;
0622:
0623: String newName = null;
0624: if (oldName != null) {
0625: newName = values.getFamily();
0626: if (oldName.equals(newName))
0627: newName = null;
0628: }
0629: int newStyle = 0;
0630: if (oldStyle == -1) {
0631: newStyle = -1;
0632: } else {
0633: if (values.getWeight() >= 2f)
0634: newStyle = BOLD;
0635: if (values.getPosture() >= .2f)
0636: newStyle |= ITALIC;
0637: if (oldStyle == newStyle)
0638: newStyle = -1;
0639: }
0640: if (handle.font2D instanceof CompositeFont) {
0641: if (newStyle != -1 || newName != null) {
0642: this .font2DHandle = FontManager.getNewComposite(
0643: newName, newStyle, handle);
0644: }
0645: } else if (newName != null) {
0646: this .createdFont = false;
0647: this .font2DHandle = null;
0648: }
0649: }
0650: initFromValues(values);
0651: }
0652:
0653: /**
0654: * Creates a new <code>Font</code> with the specified attributes.
0655: * Only keys defined in {@link java.awt.font.TextAttribute TextAttribute}
0656: * are recognized. In addition the FONT attribute is
0657: * not recognized by this constructor
0658: * (see {@link #getAvailableAttributes}). Only attributes that have
0659: * values of valid types will affect the new <code>Font</code>.
0660: * <p>
0661: * If <code>attributes</code> is <code>null</code>, a new
0662: * <code>Font</code> is initialized with default values.
0663: * @see java.awt.font.TextAttribute
0664: * @param attributes the attributes to assign to the new
0665: * <code>Font</code>, or <code>null</code>
0666: */
0667: public Font(Map<? extends Attribute, ?> attributes) {
0668: initFromValues(AttributeValues.fromMap(attributes,
0669: RECOGNIZED_MASK));
0670: }
0671:
0672: /**
0673: * Creates a new <code>Font</code> from the specified <code>font</code>.
0674: * This constructor is intended for use by subclasses.
0675: * @param font from which to create this <code>Font</code>.
0676: * @throws NullPointerException if <code>font</code> is null
0677: * @since 1.6
0678: */
0679: protected Font(Font font) {
0680: if (font.values != null) {
0681: initFromValues(font.getAttributeValues().clone());
0682: } else {
0683: this .name = font.name;
0684: this .style = font.style;
0685: this .size = font.size;
0686: this .pointSize = font.pointSize;
0687: }
0688: this .font2DHandle = font.font2DHandle;
0689: this .createdFont = font.createdFont;
0690: }
0691:
0692: /**
0693: * Font recognizes all attributes except FONT.
0694: */
0695: private static final int RECOGNIZED_MASK = AttributeValues.MASK_ALL
0696: & ~AttributeValues.getMask(EFONT);
0697:
0698: /**
0699: * These attributes are considered primary by the FONT attribute.
0700: */
0701: private static final int PRIMARY_MASK = AttributeValues.getMask(
0702: EFAMILY, EWEIGHT, EWIDTH, EPOSTURE, ESIZE, ETRANSFORM,
0703: ESUPERSCRIPT, ETRACKING);
0704:
0705: /**
0706: * These attributes are considered secondary by the FONT attribute.
0707: */
0708: private static final int SECONDARY_MASK = RECOGNIZED_MASK
0709: & ~PRIMARY_MASK;
0710:
0711: /**
0712: * These attributes are handled by layout.
0713: */
0714: private static final int LAYOUT_MASK = AttributeValues.getMask(
0715: ECHAR_REPLACEMENT, EFOREGROUND, EBACKGROUND, EUNDERLINE,
0716: ESTRIKETHROUGH, ERUN_DIRECTION, EBIDI_EMBEDDING,
0717: EJUSTIFICATION, EINPUT_METHOD_HIGHLIGHT,
0718: EINPUT_METHOD_UNDERLINE, ESWAP_COLORS, ENUMERIC_SHAPING,
0719: EKERNING, ELIGATURES, ETRACKING);
0720:
0721: private static final int EXTRA_MASK = AttributeValues.getMask(
0722: ETRANSFORM, ESUPERSCRIPT, EWIDTH);
0723:
0724: /**
0725: * Initialize the standard Font fields from the values object.
0726: */
0727: private void initFromValues(AttributeValues values) {
0728: this .values = values;
0729: values.defineAll(PRIMARY_MASK); // for 1.5 streaming compatibility
0730:
0731: this .name = values.getFamily();
0732: this .pointSize = values.getSize();
0733: this .size = (int) (values.getSize() + 0.5);
0734: if (values.getWeight() >= 2f)
0735: this .style |= BOLD; // not == 2f
0736: if (values.getPosture() >= .2f)
0737: this .style |= ITALIC; // not == .2f
0738:
0739: this .nonIdentityTx = values.anyNonDefault(EXTRA_MASK);
0740: this .hasLayoutAttributes = values.anyNonDefault(LAYOUT_MASK);
0741: }
0742:
0743: /**
0744: * Returns a <code>Font</code> appropriate to the attributes.
0745: * If <code>attributes</code>contains a <code>FONT</code> attribute
0746: * with a valid <code>Font</code> as its value, it will be
0747: * merged with any remaining attributes. See
0748: * {@link java.awt.font.TextAttribute#FONT} for more
0749: * information.
0750: *
0751: * @param attributes the attributes to assign to the new
0752: * <code>Font</code>
0753: * @return a new <code>Font</code> created with the specified
0754: * attributes
0755: * @throws NullPointerException if <code>attributes</code> is null.
0756: * @since 1.2
0757: * @see java.awt.font.TextAttribute
0758: */
0759: public static Font getFont(Map<? extends Attribute, ?> attributes) {
0760: // optimize for two cases:
0761: // 1) FONT attribute, and nothing else
0762: // 2) attributes, but no FONT
0763:
0764: // avoid turning the attributemap into a regular map for no reason
0765: if (attributes instanceof AttributeMap
0766: && ((AttributeMap) attributes).getValues() != null) {
0767: AttributeValues values = ((AttributeMap) attributes)
0768: .getValues();
0769: if (values.isNonDefault(EFONT)) {
0770: Font font = values.getFont();
0771: if (!values.anyDefined(SECONDARY_MASK)) {
0772: return font;
0773: }
0774: // merge
0775: values = font.getAttributeValues().clone();
0776: values.merge(attributes, SECONDARY_MASK);
0777: return new Font(values, font.name, font.style,
0778: font.createdFont, font.font2DHandle);
0779: }
0780: return new Font(attributes);
0781: }
0782:
0783: Font font = (Font) attributes.get(TextAttribute.FONT);
0784: if (font != null) {
0785: if (attributes.size() > 1) { // oh well, check for anything else
0786: AttributeValues values = font.getAttributeValues()
0787: .clone();
0788: values.merge(attributes, SECONDARY_MASK);
0789: return new Font(values, font.name, font.style,
0790: font.createdFont, font.font2DHandle);
0791: }
0792:
0793: return font;
0794: }
0795:
0796: return new Font(attributes);
0797: }
0798:
0799: /**
0800: * Returns a new <code>Font</code> using the specified font type
0801: * and input data. The new <code>Font</code> is
0802: * created with a point size of 1 and style {@link #PLAIN PLAIN}.
0803: * This base font can then be used with the <code>deriveFont</code>
0804: * methods in this class to derive new <code>Font</code> objects with
0805: * varying sizes, styles, transforms and font features. This
0806: * method does not close the {@link InputStream}.
0807: * <p>
0808: * To make the <code>Font</code> available to Font constructors the
0809: * returned <code>Font</code> must be registered in the
0810: * <code>GraphicsEnviroment</code> by calling
0811: * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.
0812: * @param fontFormat the type of the <code>Font</code>, which is
0813: * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified.
0814: * or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified.
0815: * @param fontStream an <code>InputStream</code> object representing the
0816: * input data for the font.
0817: * @return a new <code>Font</code> created with the specified font type.
0818: * @throws IllegalArgumentException if <code>fontFormat</code> is not
0819: * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
0820: * @throws FontFormatException if the <code>fontStream</code> data does
0821: * not contain the required font tables for the specified format.
0822: * @throws IOException if the <code>fontStream</code>
0823: * cannot be completely read.
0824: * @see GraphicsEnvironment#registerFont(Font)
0825: * @since 1.3
0826: */
0827: public static Font createFont(int fontFormat, InputStream fontStream)
0828: throws java.awt.FontFormatException, java.io.IOException {
0829:
0830: if (fontFormat != Font.TRUETYPE_FONT
0831: && fontFormat != Font.TYPE1_FONT) {
0832: throw new IllegalArgumentException(
0833: "font format not recognized");
0834: }
0835: final InputStream fStream = fontStream;
0836: Object ret = java.security.AccessController
0837: .doPrivileged(new java.security.PrivilegedAction() {
0838: public Object run() {
0839: File tFile = null;
0840: FileOutputStream outStream = null;
0841: try {
0842: tFile = File.createTempFile("+~JF", ".tmp",
0843: null);
0844: /* Temp file deleted by font shutdown hook */
0845: BufferedInputStream inStream = new BufferedInputStream(
0846: fStream);
0847: outStream = new FileOutputStream(tFile);
0848: int bytesRead = 0;
0849: int bufSize = 8192;
0850: byte[] buf = new byte[bufSize];
0851: while (bytesRead != -1) {
0852: try {
0853: bytesRead = inStream.read(buf, 0,
0854: bufSize);
0855: } catch (Throwable t) {
0856: throw new IOException();
0857: }
0858: if (bytesRead != -1) {
0859: outStream.write(buf, 0, bytesRead);
0860: }
0861: }
0862: /* don't close the input stream */
0863: outStream.close();
0864: } catch (IOException e) {
0865: if (outStream != null) {
0866: try {
0867: outStream.close();
0868: } catch (Exception e1) {
0869: }
0870: }
0871: if (tFile != null) {
0872: try {
0873: tFile.delete();
0874: } catch (Exception e2) {
0875: }
0876: }
0877: return e;
0878: }
0879: return tFile;
0880: }
0881: });
0882:
0883: if (ret instanceof File) {
0884: return new Font((File) ret, fontFormat, true);
0885: } else if (ret instanceof IOException) {
0886: throw (IOException) ret;
0887: } else {
0888: throw new FontFormatException("Couldn't access font stream");
0889: }
0890: }
0891:
0892: /**
0893: * Returns a new <code>Font</code> using the specified font type
0894: * and the specified font file. The new <code>Font</code> is
0895: * created with a point size of 1 and style {@link #PLAIN PLAIN}.
0896: * This base font can then be used with the <code>deriveFont</code>
0897: * methods in this class to derive new <code>Font</code> objects with
0898: * varying sizes, styles, transforms and font features.
0899: * @param fontFormat the type of the <code>Font</code>, which is
0900: * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is
0901: * specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is
0902: * specified.
0903: * So long as the returned font, or its derived fonts are referenced
0904: * the implementation may continue to access <code>fontFile</code>
0905: * to retrieve font data. Thus the results are undefined if the file
0906: * is changed, or becomes inaccessible.
0907: * <p>
0908: * To make the <code>Font</code> available to Font constructors the
0909: * returned <code>Font</code> must be registered in the
0910: * <code>GraphicsEnviroment</code> by calling
0911: * {@link GraphicsEnvironment#registerFont(Font) registerFont(Font)}.
0912: * @param fontFile a <code>File</code> object representing the
0913: * input data for the font.
0914: * @return a new <code>Font</code> created with the specified font type.
0915: * @throws IllegalArgumentException if <code>fontFormat</code> is not
0916: * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
0917: * @throws NullPointerException if <code>fontFile</code> is null.
0918: * @throws IOException if the <code>fontFile</code> cannot be read.
0919: * @throws FontFormatException if <code>fontFile</code> does
0920: * not contain the required font tables for the specified format.
0921: * @throws SecurityException if the executing code does not have
0922: * permission to read from the file.
0923: * @see GraphicsEnvironment#registerFont(Font)
0924: * @since 1.5
0925: */
0926: public static Font createFont(int fontFormat, File fontFile)
0927: throws java.awt.FontFormatException, java.io.IOException {
0928: if (fontFormat != Font.TRUETYPE_FONT
0929: && fontFormat != Font.TYPE1_FONT) {
0930: throw new IllegalArgumentException(
0931: "font format not recognized");
0932: }
0933: SecurityManager sm = System.getSecurityManager();
0934: if (sm != null) {
0935: FilePermission filePermission = new FilePermission(fontFile
0936: .getPath(), "read");
0937: sm.checkPermission(filePermission);
0938: }
0939: if (!fontFile.canRead()) {
0940: throw new IOException("Can't read " + fontFile);
0941: }
0942: return new Font(fontFile, fontFormat, false);
0943: }
0944:
0945: /**
0946: * Returns a copy of the transform associated with this
0947: * <code>Font</code>. This transform is not necessarily the one
0948: * used to construct the font. If the font has algorithmic
0949: * superscripting or width adjustment, this will be incorporated
0950: * into the returned <code>AffineTransform</code>.
0951: * <p>
0952: * Typically, fonts will not be transformed. Clients generally
0953: * should call {@link #isTransformed} first, and only call this
0954: * method if <code>isTransformed</code> returns true.
0955: *
0956: * @return an {@link AffineTransform} object representing the
0957: * transform attribute of this <code>Font</code> object.
0958: */
0959: public AffineTransform getTransform() {
0960: /* The most common case is the identity transform. Most callers
0961: * should call isTransformed() first, to decide if they need to
0962: * get the transform, but some may not. Here we check to see
0963: * if we have a nonidentity transform, and only do the work to
0964: * fetch and/or compute it if so, otherwise we return a new
0965: * identity transform.
0966: *
0967: * Note that the transform is _not_ necessarily the same as
0968: * the transform passed in as an Attribute in a Map, as the
0969: * transform returned will also reflect the effects of WIDTH and
0970: * SUPERSCRIPT attributes. Clients who want the actual transform
0971: * need to call getRequestedAttributes.
0972: */
0973: if (nonIdentityTx) {
0974: AttributeValues values = getAttributeValues();
0975:
0976: AffineTransform at = values.isNonDefault(ETRANSFORM) ? new AffineTransform(
0977: values.getTransform())
0978: : new AffineTransform();
0979:
0980: if (values.getSuperscript() != 0) {
0981: // can't get ascent and descent here, recursive call to this fn,
0982: // so use pointsize
0983: // let users combine super- and sub-scripting
0984:
0985: int super script = values.getSuperscript();
0986:
0987: double trans = 0;
0988: int n = 0;
0989: boolean up = super script > 0;
0990: int sign = up ? -1 : 1;
0991: int ss = up ? super script : -super script;
0992:
0993: while ((ss & 7) > n) {
0994: int newn = ss & 7;
0995: trans += sign * (ssinfo[newn] - ssinfo[n]);
0996: ss >>= 3;
0997: sign = -sign;
0998: n = newn;
0999: }
1000: trans *= pointSize;
1001: double scale = Math.pow(2. / 3., n);
1002:
1003: at.preConcatenate(AffineTransform.getTranslateInstance(
1004: 0, trans));
1005: at.scale(scale, scale);
1006:
1007: // note on placement and italics
1008: // We preconcatenate the transform because we don't want to translate along
1009: // the italic angle, but purely perpendicular to the baseline. While this
1010: // looks ok for superscripts, it can lead subscripts to stack on each other
1011: // and bring the following text too close. The way we deal with potential
1012: // collisions that can occur in the case of italics is by adjusting the
1013: // horizontal spacing of the adjacent glyphvectors. Examine the italic
1014: // angle of both vectors, if one is non-zero, compute the minimum ascent
1015: // and descent, and then the x position at each for each vector along its
1016: // italic angle starting from its (offset) baseline. Compute the difference
1017: // between the x positions and use the maximum difference to adjust the
1018: // position of the right gv.
1019: }
1020:
1021: if (values.isNonDefault(EWIDTH)) {
1022: at.scale(values.getWidth(), 1f);
1023: }
1024:
1025: return at;
1026: }
1027:
1028: return new AffineTransform();
1029: }
1030:
1031: // x = r^0 + r^1 + r^2... r^n
1032: // rx = r^1 + r^2 + r^3... r^(n+1)
1033: // x - rx = r^0 - r^(n+1)
1034: // x (1 - r) = r^0 - r^(n+1)
1035: // x = (r^0 - r^(n+1)) / (1 - r)
1036: // x = (1 - r^(n+1)) / (1 - r)
1037:
1038: // scale ratio is 2/3
1039: // trans = 1/2 of ascent * x
1040: // assume ascent is 3/4 of point size
1041:
1042: private static final float[] ssinfo = { 0.0f, 0.375f, 0.625f,
1043: 0.7916667f, 0.9027778f, 0.9768519f, 1.0262346f, 1.0591564f, };
1044:
1045: /**
1046: * Returns the family name of this <code>Font</code>.
1047: *
1048: * <p>The family name of a font is font specific. Two fonts such as
1049: * Helvetica Italic and Helvetica Bold have the same family name,
1050: * <i>Helvetica</i>, whereas their font face names are
1051: * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of
1052: * available family names may be obtained by using the
1053: * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
1054: *
1055: * <p>Use <code>getName</code> to get the logical name of the font.
1056: * Use <code>getFontName</code> to get the font face name of the font.
1057: * @return a <code>String</code> that is the family name of this
1058: * <code>Font</code>.
1059: *
1060: * @see #getName
1061: * @see #getFontName
1062: * @since JDK1.1
1063: */
1064: public String getFamily() {
1065: return getFamily_NoClientCode();
1066: }
1067:
1068: // NOTE: This method is called by privileged threads.
1069: // We implement this functionality in a package-private
1070: // method to insure that it cannot be overridden by client
1071: // subclasses.
1072: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
1073: final String getFamily_NoClientCode() {
1074: return getFamily(Locale.getDefault());
1075: }
1076:
1077: /**
1078: * Returns the family name of this <code>Font</code>, localized for
1079: * the specified locale.
1080: *
1081: * <p>The family name of a font is font specific. Two fonts such as
1082: * Helvetica Italic and Helvetica Bold have the same family name,
1083: * <i>Helvetica</i>, whereas their font face names are
1084: * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of
1085: * available family names may be obtained by using the
1086: * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
1087: *
1088: * <p>Use <code>getFontName</code> to get the font face name of the font.
1089: * @param l locale for which to get the family name
1090: * @return a <code>String</code> representing the family name of the
1091: * font, localized for the specified locale.
1092: * @see #getFontName
1093: * @see java.util.Locale
1094: * @since 1.2
1095: */
1096: public String getFamily(Locale l) {
1097: if (l == null) {
1098: throw new NullPointerException(
1099: "null locale doesn't mean default");
1100: }
1101: return getFont2D().getFamilyName(l);
1102: }
1103:
1104: /**
1105: * Returns the postscript name of this <code>Font</code>.
1106: * Use <code>getFamily</code> to get the family name of the font.
1107: * Use <code>getFontName</code> to get the font face name of the font.
1108: * @return a <code>String</code> representing the postscript name of
1109: * this <code>Font</code>.
1110: * @since 1.2
1111: */
1112: public String getPSName() {
1113: return getFont2D().getPostscriptName();
1114: }
1115:
1116: /**
1117: * Returns the logical name of this <code>Font</code>.
1118: * Use <code>getFamily</code> to get the family name of the font.
1119: * Use <code>getFontName</code> to get the font face name of the font.
1120: * @return a <code>String</code> representing the logical name of
1121: * this <code>Font</code>.
1122: * @see #getFamily
1123: * @see #getFontName
1124: * @since JDK1.0
1125: */
1126: public String getName() {
1127: return name;
1128: }
1129:
1130: /**
1131: * Returns the font face name of this <code>Font</code>. For example,
1132: * Helvetica Bold could be returned as a font face name.
1133: * Use <code>getFamily</code> to get the family name of the font.
1134: * Use <code>getName</code> to get the logical name of the font.
1135: * @return a <code>String</code> representing the font face name of
1136: * this <code>Font</code>.
1137: * @see #getFamily
1138: * @see #getName
1139: * @since 1.2
1140: */
1141: public String getFontName() {
1142: return getFontName(Locale.getDefault());
1143: }
1144:
1145: /**
1146: * Returns the font face name of the <code>Font</code>, localized
1147: * for the specified locale. For example, Helvetica Fett could be
1148: * returned as the font face name.
1149: * Use <code>getFamily</code> to get the family name of the font.
1150: * @param l a locale for which to get the font face name
1151: * @return a <code>String</code> representing the font face name,
1152: * localized for the specified locale.
1153: * @see #getFamily
1154: * @see java.util.Locale
1155: */
1156: public String getFontName(Locale l) {
1157: if (l == null) {
1158: throw new NullPointerException(
1159: "null locale doesn't mean default");
1160: }
1161: return getFont2D().getFontName(l);
1162: }
1163:
1164: /**
1165: * Returns the style of this <code>Font</code>. The style can be
1166: * PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
1167: * @return the style of this <code>Font</code>
1168: * @see #isPlain
1169: * @see #isBold
1170: * @see #isItalic
1171: * @since JDK1.0
1172: */
1173: public int getStyle() {
1174: return style;
1175: }
1176:
1177: /**
1178: * Returns the point size of this <code>Font</code>, rounded to
1179: * an integer.
1180: * Most users are familiar with the idea of using <i>point size</i> to
1181: * specify the size of glyphs in a font. This point size defines a
1182: * measurement between the baseline of one line to the baseline of the
1183: * following line in a single spaced text document. The point size is
1184: * based on <i>typographic points</i>, approximately 1/72 of an inch.
1185: * <p>
1186: * The Java(tm)2D API adopts the convention that one point is
1187: * equivalent to one unit in user coordinates. When using a
1188: * normalized transform for converting user space coordinates to
1189: * device space coordinates 72 user
1190: * space units equal 1 inch in device space. In this case one point
1191: * is 1/72 of an inch.
1192: * @return the point size of this <code>Font</code> in 1/72 of an
1193: * inch units.
1194: * @see #getSize2D
1195: * @see GraphicsConfiguration#getDefaultTransform
1196: * @see GraphicsConfiguration#getNormalizingTransform
1197: * @since JDK1.0
1198: */
1199: public int getSize() {
1200: return size;
1201: }
1202:
1203: /**
1204: * Returns the point size of this <code>Font</code> in
1205: * <code>float</code> value.
1206: * @return the point size of this <code>Font</code> as a
1207: * <code>float</code> value.
1208: * @see #getSize
1209: * @since 1.2
1210: */
1211: public float getSize2D() {
1212: return pointSize;
1213: }
1214:
1215: /**
1216: * Indicates whether or not this <code>Font</code> object's style is
1217: * PLAIN.
1218: * @return <code>true</code> if this <code>Font</code> has a
1219: * PLAIN sytle;
1220: * <code>false</code> otherwise.
1221: * @see java.awt.Font#getStyle
1222: * @since JDK1.0
1223: */
1224: public boolean isPlain() {
1225: return style == 0;
1226: }
1227:
1228: /**
1229: * Indicates whether or not this <code>Font</code> object's style is
1230: * BOLD.
1231: * @return <code>true</code> if this <code>Font</code> object's
1232: * style is BOLD;
1233: * <code>false</code> otherwise.
1234: * @see java.awt.Font#getStyle
1235: * @since JDK1.0
1236: */
1237: public boolean isBold() {
1238: return (style & BOLD) != 0;
1239: }
1240:
1241: /**
1242: * Indicates whether or not this <code>Font</code> object's style is
1243: * ITALIC.
1244: * @return <code>true</code> if this <code>Font</code> object's
1245: * style is ITALIC;
1246: * <code>false</code> otherwise.
1247: * @see java.awt.Font#getStyle
1248: * @since JDK1.0
1249: */
1250: public boolean isItalic() {
1251: return (style & ITALIC) != 0;
1252: }
1253:
1254: /**
1255: * Indicates whether or not this <code>Font</code> object has a
1256: * transform that affects its size in addition to the Size
1257: * attribute.
1258: * @return <code>true</code> if this <code>Font</code> object
1259: * has a non-identity AffineTransform attribute.
1260: * <code>false</code> otherwise.
1261: * @see java.awt.Font#getTransform
1262: * @since 1.4
1263: */
1264: public boolean isTransformed() {
1265: return nonIdentityTx;
1266: }
1267:
1268: /**
1269: * Return true if this Font contains attributes that require extra
1270: * layout processing.
1271: * @return true if the font has layout attributes
1272: * @since 1.6
1273: */
1274: public boolean hasLayoutAttributes() {
1275: return hasLayoutAttributes;
1276: }
1277:
1278: /**
1279: * Returns a <code>Font</code> object from the system properties list.
1280: * <code>nm</code> is treated as the name of a system property to be
1281: * obtained. The <code>String</code> value of this property is then
1282: * interpreted as a <code>Font</code> object according to the
1283: * specification of <code>Font.decode(String)</code>
1284: * If the specified property is not found, or the executing code does
1285: * not have permission to read the property, null is returned instead.
1286: *
1287: * @param nm the property name
1288: * @return a <code>Font</code> object that the property name
1289: * describes, or null if no such property exists.
1290: * @throws NullPointerException if nm is null.
1291: * @since 1.2
1292: * @see #decode(String)
1293: */
1294: public static Font getFont(String nm) {
1295: return getFont(nm, null);
1296: }
1297:
1298: /**
1299: * Returns the <code>Font</code> that the <code>str</code>
1300: * argument describes.
1301: * To ensure that this method returns the desired Font,
1302: * format the <code>str</code> parameter in
1303: * one of these ways
1304: * <p>
1305: * <ul>
1306: * <li><em>fontname-style-pointsize</em>
1307: * <li><em>fontname-pointsize</em>
1308: * <li><em>fontname-style</em>
1309: * <li><em>fontname</em>
1310: * <li><em>fontname style pointsize</em>
1311: * <li><em>fontname pointsize</em>
1312: * <li><em>fontname style</em>
1313: * <li><em>fontname</em>
1314: * </ul>
1315: * in which <i>style</i> is one of the four
1316: * case-insensitive strings:
1317: * <code>"PLAIN"</code>, <code>"BOLD"</code>, <code>"BOLDITALIC"</code>, or
1318: * <code>"ITALIC"</code>, and pointsize is a positive decimal integer
1319: * representation of the point size.
1320: * For example, if you want a font that is Arial, bold, with
1321: * a point size of 18, you would call this method with:
1322: * "Arial-BOLD-18".
1323: * This is equivalent to calling the Font constructor :
1324: * <code>new Font("Arial", Font.BOLD, 18);</code>
1325: * and the values are interpreted as specified by that constructor.
1326: * <p>
1327: * A valid trailing decimal field is always interpreted as the pointsize.
1328: * Therefore a fontname containing a trailing decimal value should not
1329: * be used in the fontname only form.
1330: * <p>
1331: * If a style name field is not one of the valid style strings, it is
1332: * interpreted as part of the font name, and the default style is used.
1333: * <p>
1334: * Only one of ' ' or '-' may be used to separate fields in the input.
1335: * The identified separator is the one closest to the end of the string
1336: * which separates a valid pointsize, or a valid style name from
1337: * the rest of the string.
1338: * Null (empty) pointsize and style fields are treated
1339: * as valid fields with the default value for that field.
1340: *<p>
1341: * Some font names may include the separator characters ' ' or '-'.
1342: * If <code>str</code> is not formed with 3 components, e.g. such that
1343: * <code>style</code> or <code>pointsize</code> fields are not present in
1344: * <code>str</code>, and <code>fontname</code> also contains a
1345: * character determined to be the separator character
1346: * then these characters where they appear as intended to be part of
1347: * <code>fontname</code> may instead be interpreted as separators
1348: * so the font name may not be properly recognised.
1349: *
1350: * <p>
1351: * The default size is 12 and the default style is PLAIN.
1352: * If <code>str</code> does not specify a valid size, the returned
1353: * <code>Font</code> has a size of 12. If <code>str</code> does not
1354: * specify a valid style, the returned Font has a style of PLAIN.
1355: * If you do not specify a valid font name in
1356: * the <code>str</code> argument, this method will return
1357: * a font with the family name "Dialog".
1358: * To determine what font family names are available on
1359: * your system, use the
1360: * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
1361: * If <code>str</code> is <code>null</code>, a new <code>Font</code>
1362: * is returned with the family name "Dialog", a size of 12 and a
1363: * PLAIN style.
1364: * @param str the name of the font, or <code>null</code>
1365: * @return the <code>Font</code> object that <code>str</code>
1366: * describes, or a new default <code>Font</code> if
1367: * <code>str</code> is <code>null</code>.
1368: * @see #getFamily
1369: * @since JDK1.1
1370: */
1371: public static Font decode(String str) {
1372: String fontName = str;
1373: String styleName = "";
1374: int fontSize = 12;
1375: int fontStyle = Font.PLAIN;
1376:
1377: if (str == null) {
1378: return new Font(DIALOG, fontStyle, fontSize);
1379: }
1380:
1381: int lastHyphen = str.lastIndexOf('-');
1382: int lastSpace = str.lastIndexOf(' ');
1383: char sepChar = (lastHyphen > lastSpace) ? '-' : ' ';
1384: int sizeIndex = str.lastIndexOf(sepChar);
1385: int styleIndex = str.lastIndexOf(sepChar, sizeIndex - 1);
1386: int strlen = str.length();
1387:
1388: if (sizeIndex > 0 && sizeIndex + 1 < strlen) {
1389: try {
1390: fontSize = Integer
1391: .valueOf(str.substring(sizeIndex + 1))
1392: .intValue();
1393: if (fontSize <= 0) {
1394: fontSize = 12;
1395: }
1396: } catch (NumberFormatException e) {
1397: /* It wasn't a valid size, if we didn't also find the
1398: * start of the style string perhaps this is the style */
1399: styleIndex = sizeIndex;
1400: sizeIndex = strlen;
1401: if (str.charAt(sizeIndex - 1) == sepChar) {
1402: sizeIndex--;
1403: }
1404: }
1405: }
1406:
1407: if (styleIndex >= 0 && styleIndex + 1 < strlen) {
1408: styleName = str.substring(styleIndex + 1, sizeIndex);
1409: styleName = styleName.toLowerCase(Locale.ENGLISH);
1410: if (styleName.equals("bolditalic")) {
1411: fontStyle = Font.BOLD | Font.ITALIC;
1412: } else if (styleName.equals("italic")) {
1413: fontStyle = Font.ITALIC;
1414: } else if (styleName.equals("bold")) {
1415: fontStyle = Font.BOLD;
1416: } else if (styleName.equals("plain")) {
1417: fontStyle = Font.PLAIN;
1418: } else {
1419: /* this string isn't any of the expected styles, so
1420: * assume its part of the font name
1421: */
1422: styleIndex = sizeIndex;
1423: if (str.charAt(styleIndex - 1) == sepChar) {
1424: styleIndex--;
1425: }
1426: }
1427: fontName = str.substring(0, styleIndex);
1428:
1429: } else {
1430: int fontEnd = strlen;
1431: if (styleIndex > 0) {
1432: fontEnd = styleIndex;
1433: } else if (sizeIndex > 0) {
1434: fontEnd = sizeIndex;
1435: }
1436: if (fontEnd > 0 && str.charAt(fontEnd - 1) == sepChar) {
1437: fontEnd--;
1438: }
1439: fontName = str.substring(0, fontEnd);
1440: }
1441:
1442: return new Font(fontName, fontStyle, fontSize);
1443: }
1444:
1445: /**
1446: * Gets the specified <code>Font</code> from the system properties
1447: * list. As in the <code>getProperty</code> method of
1448: * <code>System</code>, the first
1449: * argument is treated as the name of a system property to be
1450: * obtained. The <code>String</code> value of this property is then
1451: * interpreted as a <code>Font</code> object.
1452: * <p>
1453: * The property value should be one of the forms accepted by
1454: * <code>Font.decode(String)</code>
1455: * If the specified property is not found, or the executing code does not
1456: * have permission to read the property, the <code>font</code>
1457: * argument is returned instead.
1458: * @param nm the case-insensitive property name
1459: * @param font a default <code>Font</code> to return if property
1460: * <code>nm</code> is not defined
1461: * @return the <code>Font</code> value of the property.
1462: * @throws NullPointerException if nm is null.
1463: * @see #decode(String)
1464: */
1465: public static Font getFont(String nm, Font font) {
1466: String str = null;
1467: try {
1468: str = System.getProperty(nm);
1469: } catch (SecurityException e) {
1470: }
1471: if (str == null) {
1472: return font;
1473: }
1474: return decode(str);
1475: }
1476:
1477: transient int hash;
1478:
1479: /**
1480: * Returns a hashcode for this <code>Font</code>.
1481: * @return a hashcode value for this <code>Font</code>.
1482: * @since JDK1.0
1483: */
1484: public int hashCode() {
1485: if (hash == 0) {
1486: hash = name.hashCode() ^ style ^ size;
1487: /* It is possible many fonts differ only in transform.
1488: * So include the transform in the hash calculation.
1489: * nonIdentityTx is set whenever there is a transform in
1490: * 'values'. The tests for null are required because it can
1491: * also be set for other reasons.
1492: */
1493: if (nonIdentityTx && values != null
1494: && values.getTransform() != null) {
1495: hash ^= values.getTransform().hashCode();
1496: }
1497: }
1498: return hash;
1499: }
1500:
1501: /**
1502: * Compares this <code>Font</code> object to the specified
1503: * <code>Object</code>.
1504: * @param obj the <code>Object</code> to compare
1505: * @return <code>true</code> if the objects are the same
1506: * or if the argument is a <code>Font</code> object
1507: * describing the same font as this object;
1508: * <code>false</code> otherwise.
1509: * @since JDK1.0
1510: */
1511: public boolean equals(Object obj) {
1512: if (obj == this ) {
1513: return true;
1514: }
1515:
1516: if (obj != null) {
1517: try {
1518: Font font = (Font) obj;
1519: if (size == font.size
1520: && style == font.style
1521: && nonIdentityTx == font.nonIdentityTx
1522: && hasLayoutAttributes == font.hasLayoutAttributes
1523: && pointSize == font.pointSize
1524: && name.equals(font.name)) {
1525:
1526: /* 'values' is usually initialized lazily, except when
1527: * the font is constructed from a Map, or derived using
1528: * a Map or other values. So if only one font has
1529: * the field initialized we need to initialize it in
1530: * the other instance and compare.
1531: */
1532: if (values == null) {
1533: if (font.values == null) {
1534: return true;
1535: } else {
1536: return getAttributeValues().equals(
1537: font.values);
1538: }
1539: } else {
1540: return values.equals(font.getAttributeValues());
1541: }
1542: }
1543: } catch (ClassCastException e) {
1544: }
1545: }
1546: return false;
1547: }
1548:
1549: /**
1550: * Converts this <code>Font</code> object to a <code>String</code>
1551: * representation.
1552: * @return a <code>String</code> representation of this
1553: * <code>Font</code> object.
1554: * @since JDK1.0
1555: */
1556: // NOTE: This method may be called by privileged threads.
1557: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
1558: public String toString() {
1559: String strStyle;
1560:
1561: if (isBold()) {
1562: strStyle = isItalic() ? "bolditalic" : "bold";
1563: } else {
1564: strStyle = isItalic() ? "italic" : "plain";
1565: }
1566:
1567: return getClass().getName() + "[family=" + getFamily()
1568: + ",name=" + name + ",style=" + strStyle + ",size="
1569: + size + "]";
1570: } // toString()
1571:
1572: /** Serialization support. A <code>readObject</code>
1573: * method is neccessary because the constructor creates
1574: * the font's peer, and we can't serialize the peer.
1575: * Similarly the computed font "family" may be different
1576: * at <code>readObject</code> time than at
1577: * <code>writeObject</code> time. An integer version is
1578: * written so that future versions of this class will be
1579: * able to recognize serialized output from this one.
1580: */
1581: /**
1582: * The <code>Font</code> Serializable Data Form.
1583: *
1584: * @serial
1585: */
1586: private int fontSerializedDataVersion = 1;
1587:
1588: /**
1589: * Writes default serializable fields to a stream.
1590: *
1591: * @param s the <code>ObjectOutputStream</code> to write
1592: * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
1593: * @see #readObject(java.io.ObjectInputStream)
1594: */
1595: private void writeObject(java.io.ObjectOutputStream s)
1596: throws java.lang.ClassNotFoundException,
1597: java.io.IOException {
1598: if (values != null) {
1599: synchronized (values) {
1600: // transient
1601: fRequestedAttributes = values.toSerializableHashtable();
1602: s.defaultWriteObject();
1603: fRequestedAttributes = null;
1604: }
1605: } else {
1606: s.defaultWriteObject();
1607: }
1608: }
1609:
1610: /**
1611: * Reads the <code>ObjectInputStream</code>.
1612: * Unrecognized keys or values will be ignored.
1613: *
1614: * @param s the <code>ObjectInputStream</code> to read
1615: * @serial
1616: * @see #writeObject(java.io.ObjectOutputStream)
1617: */
1618: private void readObject(java.io.ObjectInputStream s)
1619: throws java.lang.ClassNotFoundException,
1620: java.io.IOException {
1621: s.defaultReadObject();
1622: if (pointSize == 0) {
1623: pointSize = (float) size;
1624: }
1625:
1626: // Handle fRequestedAttributes.
1627: // in 1.5, we always streamed out the font values plus
1628: // TRANSFORM, SUPERSCRIPT, and WIDTH, regardless of whether the
1629: // values were default or not. In 1.6 we only stream out
1630: // defined values. So, 1.6 streams in from a 1.5 stream,
1631: // it check each of these values and 'undefines' it if the
1632: // value is the default.
1633:
1634: if (fRequestedAttributes != null) {
1635: values = getAttributeValues(); // init
1636: AttributeValues extras = AttributeValues
1637: .fromSerializableHashtable(fRequestedAttributes);
1638: if (!AttributeValues.is16Hashtable(fRequestedAttributes)) {
1639: extras.unsetDefault(); // if legacy stream, undefine these
1640: }
1641: values = getAttributeValues().merge(extras);
1642: this .nonIdentityTx = values.anyNonDefault(EXTRA_MASK);
1643: this .hasLayoutAttributes = values
1644: .anyNonDefault(LAYOUT_MASK);
1645:
1646: fRequestedAttributes = null; // don't need it any more
1647: }
1648: }
1649:
1650: /**
1651: * Returns the number of glyphs in this <code>Font</code>. Glyph codes
1652: * for this <code>Font</code> range from 0 to
1653: * <code>getNumGlyphs()</code> - 1.
1654: * @return the number of glyphs in this <code>Font</code>.
1655: * @since 1.2
1656: */
1657: public int getNumGlyphs() {
1658: return getFont2D().getNumGlyphs();
1659: }
1660:
1661: /**
1662: * Returns the glyphCode which is used when this <code>Font</code>
1663: * does not have a glyph for a specified unicode code point.
1664: * @return the glyphCode of this <code>Font</code>.
1665: * @since 1.2
1666: */
1667: public int getMissingGlyphCode() {
1668: return getFont2D().getMissingGlyphCode();
1669: }
1670:
1671: /**
1672: * Returns the baseline appropriate for displaying this character.
1673: * <p>
1674: * Large fonts can support different writing systems, and each system can
1675: * use a different baseline.
1676: * The character argument determines the writing system to use. Clients
1677: * should not assume all characters use the same baseline.
1678: *
1679: * @param c a character used to identify the writing system
1680: * @return the baseline appropriate for the specified character.
1681: * @see LineMetrics#getBaselineOffsets
1682: * @see #ROMAN_BASELINE
1683: * @see #CENTER_BASELINE
1684: * @see #HANGING_BASELINE
1685: * @since 1.2
1686: */
1687: public byte getBaselineFor(char c) {
1688: return getFont2D().getBaselineFor(c);
1689: }
1690:
1691: /**
1692: * Returns a map of font attributes available in this
1693: * <code>Font</code>. Attributes include things like ligatures and
1694: * glyph substitution.
1695: * @return the attributes map of this <code>Font</code>.
1696: */
1697: public Map<TextAttribute, ?> getAttributes() {
1698: return new AttributeMap(getAttributeValues());
1699: }
1700:
1701: /**
1702: * Returns the keys of all the attributes supported by this
1703: * <code>Font</code>. These attributes can be used to derive other
1704: * fonts.
1705: * @return an array containing the keys of all the attributes
1706: * supported by this <code>Font</code>.
1707: * @since 1.2
1708: */
1709: public Attribute[] getAvailableAttributes() {
1710: // FONT is not supported by Font
1711:
1712: Attribute attributes[] = { TextAttribute.FAMILY,
1713: TextAttribute.WEIGHT, TextAttribute.WIDTH,
1714: TextAttribute.POSTURE, TextAttribute.SIZE,
1715: TextAttribute.TRANSFORM, TextAttribute.SUPERSCRIPT,
1716: TextAttribute.CHAR_REPLACEMENT,
1717: TextAttribute.FOREGROUND, TextAttribute.BACKGROUND,
1718: TextAttribute.UNDERLINE, TextAttribute.STRIKETHROUGH,
1719: TextAttribute.RUN_DIRECTION,
1720: TextAttribute.BIDI_EMBEDDING,
1721: TextAttribute.JUSTIFICATION,
1722: TextAttribute.INPUT_METHOD_HIGHLIGHT,
1723: TextAttribute.INPUT_METHOD_UNDERLINE,
1724: TextAttribute.SWAP_COLORS,
1725: TextAttribute.NUMERIC_SHAPING, TextAttribute.KERNING,
1726: TextAttribute.LIGATURES, TextAttribute.TRACKING, };
1727:
1728: return attributes;
1729: }
1730:
1731: /**
1732: * Creates a new <code>Font</code> object by replicating this
1733: * <code>Font</code> object and applying a new style and size.
1734: * @param style the style for the new <code>Font</code>
1735: * @param size the size for the new <code>Font</code>
1736: * @return a new <code>Font</code> object.
1737: * @since 1.2
1738: */
1739: public Font deriveFont(int style, float size) {
1740: if (values == null) {
1741: return new Font(name, style, size, createdFont,
1742: font2DHandle);
1743: }
1744: AttributeValues newValues = getAttributeValues().clone();
1745: int oldStyle = (this .style != style) ? this .style : -1;
1746: applyStyle(style, newValues);
1747: newValues.setSize(size);
1748: return new Font(newValues, null, oldStyle, createdFont,
1749: font2DHandle);
1750: }
1751:
1752: /**
1753: * Creates a new <code>Font</code> object by replicating this
1754: * <code>Font</code> object and applying a new style and transform.
1755: * @param style the style for the new <code>Font</code>
1756: * @param trans the <code>AffineTransform</code> associated with the
1757: * new <code>Font</code>
1758: * @return a new <code>Font</code> object.
1759: * @throws IllegalArgumentException if <code>trans</code> is
1760: * <code>null</code>
1761: * @since 1.2
1762: */
1763: public Font deriveFont(int style, AffineTransform trans) {
1764: AttributeValues newValues = getAttributeValues().clone();
1765: int oldStyle = (this .style != style) ? this .style : -1;
1766: applyStyle(style, newValues);
1767: applyTransform(trans, newValues);
1768: return new Font(newValues, null, oldStyle, createdFont,
1769: font2DHandle);
1770: }
1771:
1772: /**
1773: * Creates a new <code>Font</code> object by replicating the current
1774: * <code>Font</code> object and applying a new size to it.
1775: * @param size the size for the new <code>Font</code>.
1776: * @return a new <code>Font</code> object.
1777: * @since 1.2
1778: */
1779: public Font deriveFont(float size) {
1780: if (values == null) {
1781: return new Font(name, style, size, createdFont,
1782: font2DHandle);
1783: }
1784: AttributeValues newValues = getAttributeValues().clone();
1785: newValues.setSize(size);
1786: return new Font(newValues, null, -1, createdFont, font2DHandle);
1787: }
1788:
1789: /**
1790: * Creates a new <code>Font</code> object by replicating the current
1791: * <code>Font</code> object and applying a new transform to it.
1792: * @param trans the <code>AffineTransform</code> associated with the
1793: * new <code>Font</code>
1794: * @return a new <code>Font</code> object.
1795: * @throws IllegalArgumentException if <code>trans</code> is
1796: * <code>null</code>
1797: * @since 1.2
1798: */
1799: public Font deriveFont(AffineTransform trans) {
1800: AttributeValues newValues = getAttributeValues().clone();
1801: applyTransform(trans, newValues);
1802: return new Font(newValues, null, -1, createdFont, font2DHandle);
1803: }
1804:
1805: /**
1806: * Creates a new <code>Font</code> object by replicating the current
1807: * <code>Font</code> object and applying a new style to it.
1808: * @param style the style for the new <code>Font</code>
1809: * @return a new <code>Font</code> object.
1810: * @since 1.2
1811: */
1812: public Font deriveFont(int style) {
1813: if (values == null) {
1814: return new Font(name, style, size, createdFont,
1815: font2DHandle);
1816: }
1817: AttributeValues newValues = getAttributeValues().clone();
1818: int oldStyle = (this .style != style) ? this .style : -1;
1819: applyStyle(style, newValues);
1820: return new Font(newValues, null, oldStyle, createdFont,
1821: font2DHandle);
1822: }
1823:
1824: /**
1825: * Creates a new <code>Font</code> object by replicating the current
1826: * <code>Font</code> object and applying a new set of font attributes
1827: * to it.
1828: *
1829: * @param attributes a map of attributes enabled for the new
1830: * <code>Font</code>
1831: * @return a new <code>Font</code> object.
1832: * @since 1.2
1833: */
1834: public Font deriveFont(Map<? extends Attribute, ?> attributes) {
1835: if (attributes == null) {
1836: return this ;
1837: }
1838: AttributeValues newValues = getAttributeValues().clone();
1839: newValues.merge(attributes, RECOGNIZED_MASK);
1840:
1841: return new Font(newValues, name, style, createdFont,
1842: font2DHandle);
1843: }
1844:
1845: /**
1846: * Checks if this <code>Font</code> has a glyph for the specified
1847: * character.
1848: *
1849: * <p> <b>Note:</b> This method cannot handle <a
1850: * href="../../java/lang/Character.html#supplementary"> supplementary
1851: * characters</a>. To support all Unicode characters, including
1852: * supplementary characters, use the {@link #canDisplay(int)}
1853: * method or <code>canDisplayUpTo</code> methods.
1854: *
1855: * @param c the character for which a glyph is needed
1856: * @return <code>true</code> if this <code>Font</code> has a glyph for this
1857: * character; <code>false</code> otherwise.
1858: * @since 1.2
1859: */
1860: public boolean canDisplay(char c) {
1861: return getFont2D().canDisplay(c);
1862: }
1863:
1864: /**
1865: * Checks if this <code>Font</code> has a glyph for the specified
1866: * character.
1867: *
1868: * @param codePoint the character (Unicode code point) for which a glyph
1869: * is needed.
1870: * @return <code>true</code> if this <code>Font</code> has a glyph for the
1871: * character; <code>false</code> otherwise.
1872: * @throws IllegalArgumentException if the code point is not a valid Unicode
1873: * code point.
1874: * @see Character#isValidCodePoint(int)
1875: * @since 1.5
1876: */
1877: public boolean canDisplay(int codePoint) {
1878: if (!Character.isValidCodePoint(codePoint)) {
1879: throw new IllegalArgumentException("invalid code point: "
1880: + Integer.toHexString(codePoint));
1881: }
1882: return getFont2D().canDisplay(codePoint);
1883: }
1884:
1885: /**
1886: * Indicates whether or not this <code>Font</code> can display a
1887: * specified <code>String</code>. For strings with Unicode encoding,
1888: * it is important to know if a particular font can display the
1889: * string. This method returns an offset into the <code>String</code>
1890: * <code>str</code> which is the first character this
1891: * <code>Font</code> cannot display without using the missing glyph
1892: * code. If the <code>Font</code> can display all characters, -1 is
1893: * returned.
1894: * @param str a <code>String</code> object
1895: * @return an offset into <code>str</code> that points
1896: * to the first character in <code>str</code> that this
1897: * <code>Font</code> cannot display; or <code>-1</code> if
1898: * this <code>Font</code> can display all characters in
1899: * <code>str</code>.
1900: * @since 1.2
1901: */
1902: public int canDisplayUpTo(String str) {
1903: return canDisplayUpTo(new StringCharacterIterator(str), 0, str
1904: .length());
1905: }
1906:
1907: /**
1908: * Indicates whether or not this <code>Font</code> can display
1909: * the characters in the specified <code>text</code>
1910: * starting at <code>start</code> and ending at
1911: * <code>limit</code>. This method is a convenience overload.
1912: * @param text the specified array of <code>char</code> values
1913: * @param start the specified starting offset (in
1914: * <code>char</code>s) into the specified array of
1915: * <code>char</code> values
1916: * @param limit the specified ending offset (in
1917: * <code>char</code>s) into the specified array of
1918: * <code>char</code> values
1919: * @return an offset into <code>text</code> that points
1920: * to the first character in <code>text</code> that this
1921: * <code>Font</code> cannot display; or <code>-1</code> if
1922: * this <code>Font</code> can display all characters in
1923: * <code>text</code>.
1924: * @since 1.2
1925: */
1926: public int canDisplayUpTo(char[] text, int start, int limit) {
1927: while (start < limit && canDisplay(text[start])) {
1928: ++start;
1929: }
1930:
1931: return start == limit ? -1 : start;
1932: }
1933:
1934: /**
1935: * Indicates whether or not this <code>Font</code> can display the
1936: * text specified by the <code>iter</code> starting at
1937: * <code>start</code> and ending at <code>limit</code>.
1938: *
1939: * @param iter a {@link CharacterIterator} object
1940: * @param start the specified starting offset into the specified
1941: * <code>CharacterIterator</code>.
1942: * @param limit the specified ending offset into the specified
1943: * <code>CharacterIterator</code>.
1944: * @return an offset into <code>iter</code> that points
1945: * to the first character in <code>iter</code> that this
1946: * <code>Font</code> cannot display; or <code>-1</code> if
1947: * this <code>Font</code> can display all characters in
1948: * <code>iter</code>.
1949: * @since 1.2
1950: */
1951: public int canDisplayUpTo(CharacterIterator iter, int start,
1952: int limit) {
1953: for (char c = iter.setIndex(start); iter.getIndex() < limit
1954: && canDisplay(c); c = iter.next()) {
1955: }
1956:
1957: int result = iter.getIndex();
1958: return result == limit ? -1 : result;
1959: }
1960:
1961: /**
1962: * Returns the italic angle of this <code>Font</code>. The italic angle
1963: * is the inverse slope of the caret which best matches the posture of this
1964: * <code>Font</code>.
1965: * @see TextAttribute#POSTURE
1966: * @return the angle of the ITALIC style of this <code>Font</code>.
1967: */
1968: public float getItalicAngle() {
1969: return getItalicAngle(null);
1970: }
1971:
1972: /* The FRC hints don't affect the value of the italic angle but
1973: * we need to pass them in to look up a strike.
1974: * If we can pass in ones already being used it can prevent an extra
1975: * strike from being allocated. Note that since italic angle is
1976: * a property of the font, the font transform is needed not the
1977: * device transform. Finally, this is private but the only caller of this
1978: * in the JDK - and the only likely caller - is in this same class.
1979: */
1980: private float getItalicAngle(FontRenderContext frc) {
1981: AffineTransform at = (isTransformed()) ? getTransform()
1982: : identityTx;
1983: Object aa, fm;
1984: if (frc == null) {
1985: aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
1986: fm = RenderingHints.VALUE_FRACTIONALMETRICS_OFF;
1987: } else {
1988: aa = frc.getAntiAliasingHint();
1989: fm = frc.getFractionalMetricsHint();
1990: }
1991: return getFont2D().getItalicAngle(this , at, aa, fm);
1992: }
1993:
1994: /**
1995: * Checks whether or not this <code>Font</code> has uniform
1996: * line metrics. A logical <code>Font</code> might be a
1997: * composite font, which means that it is composed of different
1998: * physical fonts to cover different code ranges. Each of these
1999: * fonts might have different <code>LineMetrics</code>. If the
2000: * logical <code>Font</code> is a single
2001: * font then the metrics would be uniform.
2002: * @return <code>true</code> if this <code>Font</code> has
2003: * uniform line metrics; <code>false</code> otherwise.
2004: */
2005: public boolean hasUniformLineMetrics() {
2006: return false; // REMIND always safe, but prevents caller optimize
2007: }
2008:
2009: private transient SoftReference flmref;
2010:
2011: private FontLineMetrics defaultLineMetrics(FontRenderContext frc) {
2012: FontLineMetrics flm = null;
2013: if (flmref == null
2014: || (flm = (FontLineMetrics) flmref.get()) == null
2015: || !flm.frc.equals(frc)) {
2016:
2017: /* The device transform in the frc is not used in obtaining line
2018: * metrics, although it probably should be: REMIND find why not?
2019: * The font transform is used but its applied in getFontMetrics, so
2020: * just pass identity here
2021: */
2022: float[] metrics = new float[8];
2023: getFont2D().getFontMetrics(this , identityTx,
2024: frc.getAntiAliasingHint(),
2025: frc.getFractionalMetricsHint(), metrics);
2026: float ascent = metrics[0];
2027: float descent = metrics[1];
2028: float leading = metrics[2];
2029: float ssOffset = 0;
2030: if (values != null && values.getSuperscript() != 0) {
2031: ssOffset = (float) getTransform().getTranslateY();
2032: ascent -= ssOffset;
2033: descent += ssOffset;
2034: }
2035: float height = ascent + descent + leading;
2036:
2037: int baselineIndex = 0; // need real index, assumes roman for everything
2038: // need real baselines eventually
2039: float[] baselineOffsets = { 0,
2040: (descent / 2f - ascent) / 2f, -ascent };
2041:
2042: float strikethroughOffset = metrics[4];
2043: float strikethroughThickness = metrics[5];
2044:
2045: float underlineOffset = metrics[6];
2046: float underlineThickness = metrics[7];
2047:
2048: float italicAngle = getItalicAngle(frc);
2049:
2050: if (isTransformed()) {
2051: AffineTransform ctx = values.getCharTransform(); // extract rotation
2052: if (ctx != null) {
2053: Point2D.Float pt = new Point2D.Float();
2054: pt.setLocation(0, strikethroughOffset);
2055: ctx.deltaTransform(pt, pt);
2056: strikethroughOffset = pt.y;
2057: pt.setLocation(0, strikethroughThickness);
2058: ctx.deltaTransform(pt, pt);
2059: strikethroughThickness = pt.y;
2060: pt.setLocation(0, underlineOffset);
2061: ctx.deltaTransform(pt, pt);
2062: underlineOffset = pt.y;
2063: pt.setLocation(0, underlineThickness);
2064: ctx.deltaTransform(pt, pt);
2065: underlineThickness = pt.y;
2066: }
2067: }
2068: strikethroughOffset += ssOffset;
2069: underlineOffset += ssOffset;
2070:
2071: CoreMetrics cm = new CoreMetrics(ascent, descent, leading,
2072: height, baselineIndex, baselineOffsets,
2073: strikethroughOffset, strikethroughThickness,
2074: underlineOffset, underlineThickness, ssOffset,
2075: italicAngle);
2076:
2077: flm = new FontLineMetrics(0, cm, frc);
2078: flmref = new SoftReference(flm);
2079: }
2080:
2081: return (FontLineMetrics) flm.clone();
2082: }
2083:
2084: /**
2085: * Returns a {@link LineMetrics} object created with the specified
2086: * <code>String</code> and {@link FontRenderContext}.
2087: * @param str the specified <code>String</code>
2088: * @param frc the specified <code>FontRenderContext</code>
2089: * @return a <code>LineMetrics</code> object created with the
2090: * specified <code>String</code> and {@link FontRenderContext}.
2091: */
2092: public LineMetrics getLineMetrics(String str, FontRenderContext frc) {
2093: FontLineMetrics flm = defaultLineMetrics(frc);
2094: flm.numchars = str.length();
2095: return flm;
2096: }
2097:
2098: /**
2099: * Returns a <code>LineMetrics</code> object created with the
2100: * specified arguments.
2101: * @param str the specified <code>String</code>
2102: * @param beginIndex the initial offset of <code>str</code>
2103: * @param limit the end offset of <code>str</code>
2104: * @param frc the specified <code>FontRenderContext</code>
2105: * @return a <code>LineMetrics</code> object created with the
2106: * specified arguments.
2107: */
2108: public LineMetrics getLineMetrics(String str, int beginIndex,
2109: int limit, FontRenderContext frc) {
2110: FontLineMetrics flm = defaultLineMetrics(frc);
2111: int numChars = limit - beginIndex;
2112: flm.numchars = (numChars < 0) ? 0 : numChars;
2113: return flm;
2114: }
2115:
2116: /**
2117: * Returns a <code>LineMetrics</code> object created with the
2118: * specified arguments.
2119: * @param chars an array of characters
2120: * @param beginIndex the initial offset of <code>chars</code>
2121: * @param limit the end offset of <code>chars</code>
2122: * @param frc the specified <code>FontRenderContext</code>
2123: * @return a <code>LineMetrics</code> object created with the
2124: * specified arguments.
2125: */
2126: public LineMetrics getLineMetrics(char[] chars, int beginIndex,
2127: int limit, FontRenderContext frc) {
2128: FontLineMetrics flm = defaultLineMetrics(frc);
2129: int numChars = limit - beginIndex;
2130: flm.numchars = (numChars < 0) ? 0 : numChars;
2131: return flm;
2132: }
2133:
2134: /**
2135: * Returns a <code>LineMetrics</code> object created with the
2136: * specified arguments.
2137: * @param ci the specified <code>CharacterIterator</code>
2138: * @param beginIndex the initial offset in <code>ci</code>
2139: * @param limit the end offset of <code>ci</code>
2140: * @param frc the specified <code>FontRenderContext</code>
2141: * @return a <code>LineMetrics</code> object created with the
2142: * specified arguments.
2143: */
2144: public LineMetrics getLineMetrics(CharacterIterator ci,
2145: int beginIndex, int limit, FontRenderContext frc) {
2146: FontLineMetrics flm = defaultLineMetrics(frc);
2147: int numChars = limit - beginIndex;
2148: flm.numchars = (numChars < 0) ? 0 : numChars;
2149: return flm;
2150: }
2151:
2152: /**
2153: * Returns the logical bounds of the specified <code>String</code> in
2154: * the specified <code>FontRenderContext</code>. The logical bounds
2155: * contains the origin, ascent, advance, and height, which includes
2156: * the leading. The logical bounds does not always enclose all the
2157: * text. For example, in some languages and in some fonts, accent
2158: * marks can be positioned above the ascent or below the descent.
2159: * To obtain a visual bounding box, which encloses all the text,
2160: * use the {@link TextLayout#getBounds() getBounds} method of
2161: * <code>TextLayout</code>.
2162: * <p>Note: The returned bounds is in baseline-relative coordinates
2163: * (see {@link java.awt.Font class notes}).
2164: * @param str the specified <code>String</code>
2165: * @param frc the specified <code>FontRenderContext</code>
2166: * @return a {@link Rectangle2D} that is the bounding box of the
2167: * specified <code>String</code> in the specified
2168: * <code>FontRenderContext</code>.
2169: * @see FontRenderContext
2170: * @see Font#createGlyphVector
2171: * @since 1.2
2172: */
2173: public Rectangle2D getStringBounds(String str, FontRenderContext frc) {
2174: char[] array = str.toCharArray();
2175: return getStringBounds(array, 0, array.length, frc);
2176: }
2177:
2178: /**
2179: * Returns the logical bounds of the specified <code>String</code> in
2180: * the specified <code>FontRenderContext</code>. The logical bounds
2181: * contains the origin, ascent, advance, and height, which includes
2182: * the leading. The logical bounds does not always enclose all the
2183: * text. For example, in some languages and in some fonts, accent
2184: * marks can be positioned above the ascent or below the descent.
2185: * To obtain a visual bounding box, which encloses all the text,
2186: * use the {@link TextLayout#getBounds() getBounds} method of
2187: * <code>TextLayout</code>.
2188: * <p>Note: The returned bounds is in baseline-relative coordinates
2189: * (see {@link java.awt.Font class notes}).
2190: * @param str the specified <code>String</code>
2191: * @param beginIndex the initial offset of <code>str</code>
2192: * @param limit the end offset of <code>str</code>
2193: * @param frc the specified <code>FontRenderContext</code>
2194: * @return a <code>Rectangle2D</code> that is the bounding box of the
2195: * specified <code>String</code> in the specified
2196: * <code>FontRenderContext</code>.
2197: * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
2198: * less than zero, or <code>limit</code> is greater than the
2199: * length of <code>str</code>, or <code>beginIndex</code>
2200: * is greater than <code>limit</code>.
2201: * @see FontRenderContext
2202: * @see Font#createGlyphVector
2203: * @since 1.2
2204: */
2205: public Rectangle2D getStringBounds(String str, int beginIndex,
2206: int limit, FontRenderContext frc) {
2207: String substr = str.substring(beginIndex, limit);
2208: return getStringBounds(substr, frc);
2209: }
2210:
2211: /**
2212: * Returns the logical bounds of the specified array of characters
2213: * in the specified <code>FontRenderContext</code>. The logical
2214: * bounds contains the origin, ascent, advance, and height, which
2215: * includes the leading. The logical bounds does not always enclose
2216: * all the text. For example, in some languages and in some fonts,
2217: * accent marks can be positioned above the ascent or below the
2218: * descent. To obtain a visual bounding box, which encloses all the
2219: * text, use the {@link TextLayout#getBounds() getBounds} method of
2220: * <code>TextLayout</code>.
2221: * <p>Note: The returned bounds is in baseline-relative coordinates
2222: * (see {@link java.awt.Font class notes}).
2223: * @param chars an array of characters
2224: * @param beginIndex the initial offset in the array of
2225: * characters
2226: * @param limit the end offset in the array of characters
2227: * @param frc the specified <code>FontRenderContext</code>
2228: * @return a <code>Rectangle2D</code> that is the bounding box of the
2229: * specified array of characters in the specified
2230: * <code>FontRenderContext</code>.
2231: * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
2232: * less than zero, or <code>limit</code> is greater than the
2233: * length of <code>chars</code>, or <code>beginIndex</code>
2234: * is greater than <code>limit</code>.
2235: * @see FontRenderContext
2236: * @see Font#createGlyphVector
2237: * @since 1.2
2238: */
2239: public Rectangle2D getStringBounds(char[] chars, int beginIndex,
2240: int limit, FontRenderContext frc) {
2241: if (beginIndex < 0) {
2242: throw new IndexOutOfBoundsException("beginIndex: "
2243: + beginIndex);
2244: }
2245: if (limit > chars.length) {
2246: throw new IndexOutOfBoundsException("limit: " + limit);
2247: }
2248: if (beginIndex > limit) {
2249: throw new IndexOutOfBoundsException("range length: "
2250: + (limit - beginIndex));
2251: }
2252:
2253: // this code should be in textlayout
2254: // quick check for simple text, assume GV ok to use if simple
2255:
2256: boolean simple = values == null
2257: || (values.getKerning() == 0
2258: && values.getLigatures() == 0 && values
2259: .getBaselineTransform() == null);
2260: if (simple) {
2261: simple = !FontManager.isComplexText(chars, beginIndex,
2262: limit);
2263: }
2264:
2265: if (simple) {
2266: GlyphVector gv = new StandardGlyphVector(this , chars,
2267: beginIndex, limit - beginIndex, frc);
2268: return gv.getLogicalBounds();
2269: } else {
2270: // need char array constructor on textlayout
2271: String str = new String(chars, beginIndex, limit
2272: - beginIndex);
2273: TextLayout tl = new TextLayout(str, this , frc);
2274: return new Rectangle2D.Float(0, -tl.getAscent(), tl
2275: .getAdvance(), tl.getAscent() + tl.getDescent()
2276: + tl.getLeading());
2277: }
2278: }
2279:
2280: /**
2281: * Returns the logical bounds of the characters indexed in the
2282: * specified {@link CharacterIterator} in the
2283: * specified <code>FontRenderContext</code>. The logical bounds
2284: * contains the origin, ascent, advance, and height, which includes
2285: * the leading. The logical bounds does not always enclose all the
2286: * text. For example, in some languages and in some fonts, accent
2287: * marks can be positioned above the ascent or below the descent.
2288: * To obtain a visual bounding box, which encloses all the text,
2289: * use the {@link TextLayout#getBounds() getBounds} method of
2290: * <code>TextLayout</code>.
2291: * <p>Note: The returned bounds is in baseline-relative coordinates
2292: * (see {@link java.awt.Font class notes}).
2293: * @param ci the specified <code>CharacterIterator</code>
2294: * @param beginIndex the initial offset in <code>ci</code>
2295: * @param limit the end offset in <code>ci</code>
2296: * @param frc the specified <code>FontRenderContext</code>
2297: * @return a <code>Rectangle2D</code> that is the bounding box of the
2298: * characters indexed in the specified <code>CharacterIterator</code>
2299: * in the specified <code>FontRenderContext</code>.
2300: * @see FontRenderContext
2301: * @see Font#createGlyphVector
2302: * @since 1.2
2303: * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
2304: * less than the start index of <code>ci</code>, or
2305: * <code>limit</code> is greater than the end index of
2306: * <code>ci</code>, or <code>beginIndex</code> is greater
2307: * than <code>limit</code>
2308: */
2309: public Rectangle2D getStringBounds(CharacterIterator ci,
2310: int beginIndex, int limit, FontRenderContext frc) {
2311: int start = ci.getBeginIndex();
2312: int end = ci.getEndIndex();
2313:
2314: if (beginIndex < start) {
2315: throw new IndexOutOfBoundsException("beginIndex: "
2316: + beginIndex);
2317: }
2318: if (limit > end) {
2319: throw new IndexOutOfBoundsException("limit: " + limit);
2320: }
2321: if (beginIndex > limit) {
2322: throw new IndexOutOfBoundsException("range length: "
2323: + (limit - beginIndex));
2324: }
2325:
2326: char[] arr = new char[limit - beginIndex];
2327:
2328: ci.setIndex(beginIndex);
2329: for (int idx = 0; idx < arr.length; idx++) {
2330: arr[idx] = ci.current();
2331: ci.next();
2332: }
2333:
2334: return getStringBounds(arr, 0, arr.length, frc);
2335: }
2336:
2337: /**
2338: * Returns the bounds for the character with the maximum
2339: * bounds as defined in the specified <code>FontRenderContext</code>.
2340: * <p>Note: The returned bounds is in baseline-relative coordinates
2341: * (see {@link java.awt.Font class notes}).
2342: * @param frc the specified <code>FontRenderContext</code>
2343: * @return a <code>Rectangle2D</code> that is the bounding box
2344: * for the character with the maximum bounds.
2345: */
2346: public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
2347: float[] metrics = new float[4];
2348:
2349: getFont2D().getFontMetrics(this , frc, metrics);
2350:
2351: return new Rectangle2D.Float(0, -metrics[0], metrics[3],
2352: metrics[0] + metrics[1] + metrics[2]);
2353: }
2354:
2355: /**
2356: * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2357: * mapping characters to glyphs one-to-one based on the
2358: * Unicode cmap in this <code>Font</code>. This method does no other
2359: * processing besides the mapping of glyphs to characters. This
2360: * means that this method is not useful for some scripts, such
2361: * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2362: * shaping, or ligature substitution.
2363: * @param frc the specified <code>FontRenderContext</code>
2364: * @param str the specified <code>String</code>
2365: * @return a new <code>GlyphVector</code> created with the
2366: * specified <code>String</code> and the specified
2367: * <code>FontRenderContext</code>.
2368: */
2369: public GlyphVector createGlyphVector(FontRenderContext frc,
2370: String str) {
2371: return (GlyphVector) new StandardGlyphVector(this , str, frc);
2372: }
2373:
2374: /**
2375: * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2376: * mapping characters to glyphs one-to-one based on the
2377: * Unicode cmap in this <code>Font</code>. This method does no other
2378: * processing besides the mapping of glyphs to characters. This
2379: * means that this method is not useful for some scripts, such
2380: * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2381: * shaping, or ligature substitution.
2382: * @param frc the specified <code>FontRenderContext</code>
2383: * @param chars the specified array of characters
2384: * @return a new <code>GlyphVector</code> created with the
2385: * specified array of characters and the specified
2386: * <code>FontRenderContext</code>.
2387: */
2388: public GlyphVector createGlyphVector(FontRenderContext frc,
2389: char[] chars) {
2390: return (GlyphVector) new StandardGlyphVector(this , chars, frc);
2391: }
2392:
2393: /**
2394: * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2395: * mapping the specified characters to glyphs one-to-one based on the
2396: * Unicode cmap in this <code>Font</code>. This method does no other
2397: * processing besides the mapping of glyphs to characters. This
2398: * means that this method is not useful for some scripts, such
2399: * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2400: * shaping, or ligature substitution.
2401: * @param frc the specified <code>FontRenderContext</code>
2402: * @param ci the specified <code>CharacterIterator</code>
2403: * @return a new <code>GlyphVector</code> created with the
2404: * specified <code>CharacterIterator</code> and the specified
2405: * <code>FontRenderContext</code>.
2406: */
2407: public GlyphVector createGlyphVector(FontRenderContext frc,
2408: CharacterIterator ci) {
2409: return (GlyphVector) new StandardGlyphVector(this , ci, frc);
2410: }
2411:
2412: /**
2413: * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2414: * mapping characters to glyphs one-to-one based on the
2415: * Unicode cmap in this <code>Font</code>. This method does no other
2416: * processing besides the mapping of glyphs to characters. This
2417: * means that this method is not useful for some scripts, such
2418: * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2419: * shaping, or ligature substitution.
2420: * @param frc the specified <code>FontRenderContext</code>
2421: * @param glyphCodes the specified integer array
2422: * @return a new <code>GlyphVector</code> created with the
2423: * specified integer array and the specified
2424: * <code>FontRenderContext</code>.
2425: */
2426: public GlyphVector createGlyphVector(FontRenderContext frc,
2427: int[] glyphCodes) {
2428: return (GlyphVector) new StandardGlyphVector(this , glyphCodes,
2429: frc);
2430: }
2431:
2432: /**
2433: * Returns a new <code>GlyphVector</code> object, performing full
2434: * layout of the text if possible. Full layout is required for
2435: * complex text, such as Arabic or Hindi. Support for different
2436: * scripts depends on the font and implementation.
2437: * <p>
2438: * Layout requires bidi analysis, as performed by
2439: * <code>Bidi</code>, and should only be performed on text that
2440: * has a uniform direction. The direction is indicated in the
2441: * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a
2442: * right-to-left (Arabic and Hebrew) run direction, or
2443: * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English)
2444: * run direction.
2445: * <p>
2446: * In addition, some operations, such as Arabic shaping, require
2447: * context, so that the characters at the start and limit can have
2448: * the proper shapes. Sometimes the data in the buffer outside
2449: * the provided range does not have valid data. The values
2450: * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be
2451: * added to the flags parameter to indicate that the text before
2452: * start, or after limit, respectively, should not be examined
2453: * for context.
2454: * <p>
2455: * All other values for the flags parameter are reserved.
2456: *
2457: * @param frc the specified <code>FontRenderContext</code>
2458: * @param text the text to layout
2459: * @param start the start of the text to use for the <code>GlyphVector</code>
2460: * @param limit the limit of the text to use for the <code>GlyphVector</code>
2461: * @param flags control flags as described above
2462: * @return a new <code>GlyphVector</code> representing the text between
2463: * start and limit, with glyphs chosen and positioned so as to best represent
2464: * the text
2465: * @throws ArrayIndexOutOfBoundsException if start or limit is
2466: * out of bounds
2467: * @see java.text.Bidi
2468: * @see #LAYOUT_LEFT_TO_RIGHT
2469: * @see #LAYOUT_RIGHT_TO_LEFT
2470: * @see #LAYOUT_NO_START_CONTEXT
2471: * @see #LAYOUT_NO_LIMIT_CONTEXT
2472: * @since 1.4
2473: */
2474: public GlyphVector layoutGlyphVector(FontRenderContext frc,
2475: char[] text, int start, int limit, int flags) {
2476:
2477: GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines
2478: StandardGlyphVector gv = gl.layout(this , frc, text, start,
2479: limit - start, flags, null);
2480: GlyphLayout.done(gl);
2481: return gv;
2482: }
2483:
2484: /**
2485: * A flag to layoutGlyphVector indicating that text is left-to-right as
2486: * determined by Bidi analysis.
2487: */
2488: public static final int LAYOUT_LEFT_TO_RIGHT = 0;
2489:
2490: /**
2491: * A flag to layoutGlyphVector indicating that text is right-to-left as
2492: * determined by Bidi analysis.
2493: */
2494: public static final int LAYOUT_RIGHT_TO_LEFT = 1;
2495:
2496: /**
2497: * A flag to layoutGlyphVector indicating that text in the char array
2498: * before the indicated start should not be examined.
2499: */
2500: public static final int LAYOUT_NO_START_CONTEXT = 2;
2501:
2502: /**
2503: * A flag to layoutGlyphVector indicating that text in the char array
2504: * after the indicated limit should not be examined.
2505: */
2506: public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
2507:
2508: private static void applyTransform(AffineTransform trans,
2509: AttributeValues values) {
2510: if (trans == null) {
2511: throw new IllegalArgumentException(
2512: "transform must not be null");
2513: }
2514: values.setTransform(trans);
2515: }
2516:
2517: private static void applyStyle(int style, AttributeValues values) {
2518: // WEIGHT_BOLD, WEIGHT_REGULAR
2519: values.setWeight((style & BOLD) != 0 ? 2f : 1f);
2520: // POSTURE_OBLIQUE, POSTURE_REGULAR
2521: values.setPosture((style & ITALIC) != 0 ? .2f : 0f);
2522: }
2523:
2524: /*
2525: * Initialize JNI field and method IDs
2526: */
2527: private static native void initIDs();
2528: }
|