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