1. /*
  2. * @(#)Font.java 1.200 04/07/20
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.awt.font.FontRenderContext;
  9. import java.awt.font.GlyphVector;
  10. import java.awt.font.LineMetrics;
  11. import java.awt.font.TextAttribute;
  12. import java.awt.font.TextLayout;
  13. import java.awt.font.TransformAttribute;
  14. import java.awt.geom.AffineTransform;
  15. import java.awt.geom.Rectangle2D;
  16. import java.awt.peer.FontPeer;
  17. import java.io.*;
  18. import java.lang.ref.SoftReference;
  19. import java.text.AttributedCharacterIterator.Attribute;
  20. import java.text.CharacterIterator;
  21. import java.text.StringCharacterIterator;
  22. import java.util.HashMap;
  23. import java.util.Hashtable;
  24. import java.util.Locale;
  25. import java.util.Map;
  26. import sun.font.StandardGlyphVector;
  27. import sun.java2d.FontSupport;
  28. import sun.font.Font2D;
  29. import sun.font.Font2DHandle;
  30. import sun.font.FontManager;
  31. import sun.font.GlyphLayout;
  32. import sun.font.FontLineMetrics;
  33. import sun.font.CoreMetrics;
  34. /**
  35. * The <code>Font</code> class represents fonts, which are used to
  36. * render text in a visible way.
  37. * A font provides the information needed to map sequences of
  38. * <em>characters</em> to sequences of <em>glyphs</em>
  39. * and to render sequences of glyphs on <code>Graphics</code> and
  40. * <code>Component</code> objects.
  41. *
  42. * <h4>Characters and Glyphs</h4>
  43. *
  44. * A <em>character</em> is a symbol that represents an item such as a letter,
  45. * a digit, or punctuation in an abstract way. For example, <code>'g'</code>,
  46. * <font size=-1>LATIN SMALL LETTER G</font>, is a character.
  47. * <p>
  48. * A <em>glyph</em> is a shape used to render a character or a sequence of
  49. * characters. In simple writing systems, such as Latin, typically one glyph
  50. * represents one character. In general, however, characters and glyphs do not
  51. * have one-to-one correspondence. For example, the character 'á'
  52. * <font size=-1>LATIN SMALL LETTER A WITH ACUTE</font>, can be represented by
  53. * two glyphs: one for 'a' and one for '´'. On the other hand, the
  54. * two-character string "fi" can be represented by a single glyph, an
  55. * "fi" ligature. In complex writing systems, such as Arabic or the South
  56. * and South-East Asian writing systems, the relationship between characters
  57. * and glyphs can be more complicated and involve context-dependent selection
  58. * of glyphs as well as glyph reordering.
  59. *
  60. * A font encapsulates the collection of glyphs needed to render a selected set
  61. * of characters as well as the tables needed to map sequences of characters to
  62. * corresponding sequences of glyphs.
  63. *
  64. * <h4>Physical and Logical Fonts</h4>
  65. *
  66. * The Java 2 platform distinguishes between two kinds of fonts:
  67. * <em>physical</em> fonts and <em>logical</em> fonts.
  68. * <p>
  69. * <em>Physical</em> fonts are the actual font libraries containing glyph data
  70. * and tables to map from character sequences to glyph sequences, using a font
  71. * technology such as TrueType or PostScript Type 1.
  72. * All implementations of the Java 2 platform must support TrueType fonts;
  73. * support for other font technologies is implementation dependent.
  74. * Physical fonts may use names such as Helvetica, Palatino, HonMincho, or
  75. * any number of other font names.
  76. * Typically, each physical font supports only a limited set of writing
  77. * systems, for example, only Latin characters or only Japanese and Basic
  78. * Latin.
  79. * The set of available physical fonts varies between configurations.
  80. * Applications that require specific fonts can bundle them and instantiate
  81. * them using the {@link #createFont createFont} method.
  82. * <p>
  83. * <em>Logical</em> fonts are the five font families defined by the Java
  84. * platform which must be supported by any Java runtime environment:
  85. * Serif, SansSerif, Monospaced, Dialog, and DialogInput.
  86. * These logical fonts are not actual font libraries. Instead, the logical
  87. * font names are mapped to physical fonts by the Java runtime environment.
  88. * The mapping is implementation and usually locale dependent, so the look
  89. * and the metrics provided by them vary.
  90. * Typically, each logical font name maps to several physical fonts in order to
  91. * cover a large range of characters.
  92. * <p>
  93. * Peered AWT components, such as {@link Label Label} and
  94. * {@link TextField TextField}, can only use logical fonts.
  95. * <p>
  96. * For a discussion of the relative advantages and disadvantages of using
  97. * physical or logical fonts, see the
  98. * <a href="http://java.sun.com/j2se/corejava/intl/reference/faqs/index.html#desktop-rendering">Internationalization FAQ</a>
  99. * document.
  100. *
  101. * <h4>Font Faces and Names</h4>
  102. *
  103. * A <code>Font</code>
  104. * can have many faces, such as heavy, medium, oblique, gothic and
  105. * regular. All of these faces have similar typographic design.
  106. * <p>
  107. * There are three different names that you can get from a
  108. * <code>Font</code> object. The <em>logical font name</em> is simply the
  109. * name that was used to construct the font.
  110. * The <em>font face name</em>, or just <em>font name</em> for
  111. * short, is the name of a particular font face, like Helvetica Bold. The
  112. * <em>family name</em> is the name of the font family that determines the
  113. * typographic design across several faces, like Helvetica.
  114. * <p>
  115. * The <code>Font</code> class represents an instance of a font face from
  116. * a collection of font faces that are present in the system resources
  117. * of the host system. As examples, Arial Bold and Courier Bold Italic
  118. * are font faces. There can be several <code>Font</code> objects
  119. * associated with a font face, each differing in size, style, transform
  120. * and font features.
  121. * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method
  122. * of the <code>GraphicsEnvironment</code> class returns an
  123. * array of all font faces available in the system. These font faces are
  124. * returned as <code>Font</code> objects with a size of 1, identity
  125. * transform and default font features. These
  126. * base fonts can then be used to derive new <code>Font</code> objects
  127. * with varying sizes, styles, transforms and font features via the
  128. * <code>deriveFont</code> methods in this class.
  129. *
  130. * @version 1.200, 07/20/04
  131. */
  132. public class Font implements java.io.Serializable
  133. {
  134. static {
  135. /* ensure that the necessary native libraries are loaded */
  136. Toolkit.loadLibraries();
  137. initIDs();
  138. }
  139. /**
  140. * A map of font attributes available in this font.
  141. * Attributes include things like ligatures and glyph substitution.
  142. *
  143. * @serial
  144. * @see #getAttributes()
  145. */
  146. private Hashtable fRequestedAttributes;
  147. private static final Map EMPTY_MAP = new Hashtable(5, (float)0.9);
  148. private static final TransformAttribute IDENT_TX_ATTRIBUTE =
  149. new TransformAttribute(new AffineTransform());
  150. /*
  151. * Constants to be used for styles. Can be combined to mix
  152. * styles.
  153. */
  154. /**
  155. * The plain style constant.
  156. */
  157. public static final int PLAIN = 0;
  158. /**
  159. * The bold style constant. This can be combined with the other style
  160. * constants (except PLAIN) for mixed styles.
  161. */
  162. public static final int BOLD = 1;
  163. /**
  164. * The italicized style constant. This can be combined with the other
  165. * style constants (except PLAIN) for mixed styles.
  166. */
  167. public static final int ITALIC = 2;
  168. /**
  169. * The baseline used in most Roman scripts when laying out text.
  170. */
  171. public static final int ROMAN_BASELINE = 0;
  172. /**
  173. * The baseline used in ideographic scripts like Chinese, Japanese,
  174. * and Korean when laying out text.
  175. */
  176. public static final int CENTER_BASELINE = 1;
  177. /**
  178. * The baseline used in Devanigiri and similar scripts when laying
  179. * out text.
  180. */
  181. public static final int HANGING_BASELINE = 2;
  182. /**
  183. * Identify a font resource of type TRUETYPE.
  184. * Used to specify a TrueType font resource to the
  185. * {@link #createFont} method.
  186. * @since 1.3
  187. */
  188. public static final int TRUETYPE_FONT = 0;
  189. /**
  190. * Identify a font resource of type TYPE1.
  191. * Used to specify a Type1 font resource to the
  192. * {@link #createFont} method.
  193. * @since 1.5
  194. */
  195. public static final int TYPE1_FONT = 1;
  196. /**
  197. * The logical name of this <code>Font</code>, as passed to the
  198. * constructor.
  199. * @since JDK1.0
  200. *
  201. * @serial
  202. * @see #getName
  203. */
  204. protected String name;
  205. /**
  206. * The style of this <code>Font</code>, as passed to the constructor.
  207. * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
  208. * @since JDK1.0
  209. *
  210. * @serial
  211. * @see #getStyle()
  212. */
  213. protected int style;
  214. /**
  215. * The point size of this <code>Font</code>, rounded to integer.
  216. * @since JDK1.0
  217. *
  218. * @serial
  219. * @see #getSize()
  220. */
  221. protected int size;
  222. /**
  223. * The point size of this <code>Font</code> in <code>float</code>.
  224. *
  225. * @serial
  226. * @see #getSize()
  227. * @see #getSize2D()
  228. */
  229. protected float pointSize;
  230. /**
  231. * The platform specific font information.
  232. */
  233. private transient FontPeer peer;
  234. private transient long pData; // native JDK1.1 font pointer
  235. private transient Font2DHandle font2DHandle;
  236. private transient int superscript;
  237. private transient float width = 1f;
  238. /*
  239. * If the origin of a Font is a created font then this attribute
  240. * must be set on all derived fonts too.
  241. */
  242. private transient boolean createdFont = false;
  243. // cached values - performance
  244. private transient double[] matrix;
  245. private transient boolean nonIdentityTx;
  246. private static final AffineTransform identityTx = new AffineTransform();
  247. /*
  248. * JDK 1.1 serialVersionUID
  249. */
  250. private static final long serialVersionUID = -4206021311591459213L;
  251. /**
  252. * Gets the peer of this <code>Font</code>.
  253. * @return the peer of the <code>Font</code>.
  254. * @since JDK1.1
  255. * @deprecated Font rendering is now platform independent.
  256. */
  257. @Deprecated
  258. public FontPeer getPeer(){
  259. return getPeer_NoClientCode();
  260. }
  261. // NOTE: This method is called by privileged threads.
  262. // We implement this functionality in a package-private method
  263. // to insure that it cannot be overridden by client subclasses.
  264. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  265. final FontPeer getPeer_NoClientCode() {
  266. if(peer == null) {
  267. Toolkit tk = Toolkit.getDefaultToolkit();
  268. this.peer = tk.getFontPeer(name, style);
  269. }
  270. return peer;
  271. }
  272. /* create this map only when requested - which may be rarely */
  273. private Hashtable getRequestedAttributes() {
  274. if (fRequestedAttributes == null) {
  275. fRequestedAttributes = new Hashtable(7, (float)0.9);
  276. fRequestedAttributes.put(TextAttribute.TRANSFORM,
  277. IDENT_TX_ATTRIBUTE);
  278. fRequestedAttributes.put(TextAttribute.FAMILY, name);
  279. fRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
  280. fRequestedAttributes.put(TextAttribute.WEIGHT,
  281. (style & BOLD) != 0 ?
  282. TextAttribute.WEIGHT_BOLD :
  283. TextAttribute.WEIGHT_REGULAR);
  284. fRequestedAttributes.put(TextAttribute.POSTURE,
  285. (style & ITALIC) != 0 ?
  286. TextAttribute.POSTURE_OBLIQUE :
  287. TextAttribute.POSTURE_REGULAR);
  288. fRequestedAttributes.put(TextAttribute.SUPERSCRIPT,
  289. new Integer(superscript));
  290. fRequestedAttributes.put(TextAttribute.WIDTH,
  291. new Float(width));
  292. }
  293. return fRequestedAttributes;
  294. }
  295. private void initializeFont(Hashtable attributes) {
  296. if (attributes != null) {
  297. Object obj = attributes.get(TextAttribute.TRANSFORM);
  298. if (obj instanceof TransformAttribute) {
  299. nonIdentityTx = !((TransformAttribute)obj).isIdentity();
  300. } else if (obj instanceof AffineTransform) {
  301. nonIdentityTx = !((AffineTransform)obj).isIdentity();
  302. }
  303. obj = attributes.get(TextAttribute.SUPERSCRIPT);
  304. if (obj instanceof Integer) {
  305. superscript = ((Integer)obj).intValue();
  306. // !!! always synthesize superscript
  307. nonIdentityTx |= superscript != 0;
  308. }
  309. obj = attributes.get(TextAttribute.WIDTH);
  310. if (obj instanceof Integer) {
  311. width = ((Float)obj).floatValue();
  312. // !!! always synthesize width
  313. nonIdentityTx |= width != 1;
  314. }
  315. }
  316. }
  317. private Font2D getFont2D() {
  318. if (FontManager.usingPerAppContextComposites &&
  319. font2DHandle != null &&
  320. font2DHandle.font2D instanceof sun.font.CompositeFont &&
  321. ((sun.font.CompositeFont)(font2DHandle.font2D)).isStdComposite()) {
  322. return FontManager.findFont2D(name, style,
  323. FontManager.LOGICAL_FALLBACK);
  324. } else if (font2DHandle == null) {
  325. font2DHandle =
  326. FontManager.findFont2D(name, style,
  327. FontManager.LOGICAL_FALLBACK).handle;
  328. }
  329. /* Do not cache the de-referenced font2D. It must be explicitly
  330. * de-referenced to pick up a valid font in the event that the
  331. * original one is marked invalid
  332. */
  333. return font2DHandle.font2D;
  334. }
  335. /**
  336. * Creates a new <code>Font</code> from the specified name, style and
  337. * point size.
  338. * <p>
  339. * The font name can be a font face name or a font family name.
  340. * It is used together with the style to find an appropriate font face.
  341. * When a font family name is specified, the style argument is used to
  342. * select the most appropriate face from the family. When a font face
  343. * name is specified, the face's style and the style argument are
  344. * merged to locate the best matching font from the same family.
  345. * For example if face name "Arial Bold" is specified with style
  346. * <code>Font.ITALIC</code>, the font system looks for a face in the
  347. * "Arial" family that is bold and italic, and may associate the font
  348. * instance with the physical font face "Arial Bold Italic".
  349. * The style argument is merged with the specified face's style, not
  350. * added or subtracted.
  351. * This means, specifying a bold face and a bold style does not
  352. * double-embolden the font, and specifying a bold face and a plain
  353. * style does not lighten the font.
  354. * <p>
  355. * If no face for the requested style can be found, the font system
  356. * may apply algorithmic styling to achieve the desired style.
  357. * For example, if <code>ITALIC</code> is requested, but no italic
  358. * face is available, glyphs from the plain face may be algorithmically
  359. * obliqued (slanted).
  360. * <p>
  361. * Font name lookup is case insensitive, using the case folding
  362. * rules of the US locale.
  363. *
  364. * @param name the font name. This can be a font face name or a font
  365. * family name, and may represent either a logical font or a physical
  366. * font found in this <code>GraphicsEnvironment</code>.
  367. * The family names for logical fonts are: Dialog, DialogInput,
  368. * Monospaced, Serif, or SansSerif. If <code>name</code> is
  369. * <code>null</code>, the <em>logical font name</em> of the new
  370. * <code>Font</code> as returned by <code>getName()</code>is set to
  371. * the name "Default".
  372. * @param style the style constant for the <code>Font</code>
  373. * The style argument is an integer bitmask that may
  374. * be PLAIN, or a bitwise union of BOLD and/or ITALIC
  375. * (for example, ITALIC or BOLD|ITALIC).
  376. * If the style argument does not conform to one of the expected
  377. * integer bitmasks then the style is set to PLAIN.
  378. * @param size the point size of the <code>Font</code>
  379. * @see GraphicsEnvironment#getAllFonts
  380. * @see GraphicsEnvironment#getAvailableFontFamilyNames
  381. * @since JDK1.0
  382. */
  383. public Font(String name, int style, int size) {
  384. this.name = (name != null) ? name : "Default";
  385. this.style = (style & ~0x03) == 0 ? style : 0;
  386. this.size = size;
  387. this.pointSize = size;
  388. }
  389. private Font(String name, int style, float sizePts) {
  390. this.name = (name != null) ? name : "Default";
  391. this.style = (style & ~0x03) == 0 ? style : 0;
  392. this.size = (int)(sizePts + 0.5);
  393. this.pointSize = sizePts;
  394. }
  395. /* used to implement Font.createFont */
  396. private Font(File fontFile, int fontFormat, boolean isCopy)
  397. throws FontFormatException {
  398. this.createdFont = true;
  399. /* Font2D instances created by this method track their font file
  400. * so that when the Font2D is GC'd it can also remove the file.
  401. */
  402. this.font2DHandle =
  403. FontManager.createFont2D(fontFile, fontFormat, isCopy).handle;
  404. this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
  405. this.style = Font.PLAIN;
  406. this.size = 1;
  407. this.pointSize = 1f;
  408. }
  409. private Font(Map attributes, boolean created, Font2DHandle handle) {
  410. this.createdFont = created;
  411. /* Fonts created from a stream will use the same font2D instance
  412. * as the parent.
  413. */
  414. if (created) {
  415. this.font2DHandle = handle;
  416. }
  417. initFromMap(attributes);
  418. }
  419. /**
  420. * Creates a new <code>Font</code> with the specified attributes.
  421. * This <code>Font</code> only recognizes keys defined in
  422. * {@link TextAttribute} as attributes. If <code>attributes</code>
  423. * is <code>null</code>, a new <code>Font</code> is initialized
  424. * with default attributes.
  425. * @param attributes the attributes to assign to the new
  426. * <code>Font</code>, or <code>null</code>
  427. */
  428. public Font(Map<? extends Attribute, ?> attributes) {
  429. initFromMap(attributes);
  430. }
  431. private void initFromMap(Map attributes) {
  432. this.name = "Dialog";
  433. this.pointSize = 12;
  434. this.size = 12;
  435. if((attributes != null) &&
  436. (!attributes.equals(EMPTY_MAP)))
  437. {
  438. Object obj;
  439. fRequestedAttributes = new Hashtable(attributes);
  440. if ((obj = attributes.get(TextAttribute.FAMILY)) != null) {
  441. this.name = (String)obj;
  442. }
  443. if ((obj = attributes.get(TextAttribute.WEIGHT)) != null) {
  444. if(obj.equals(TextAttribute.WEIGHT_BOLD)) {
  445. this.style |= BOLD;
  446. }
  447. }
  448. if ((obj = attributes.get(TextAttribute.POSTURE)) != null) {
  449. if(obj.equals(TextAttribute.POSTURE_OBLIQUE)) {
  450. this.style |= ITALIC;
  451. }
  452. }
  453. if ((obj = attributes.get(TextAttribute.SIZE)) != null) {
  454. this.pointSize = ((Float)obj).floatValue();
  455. this.size = (int)(this.pointSize + 0.5);
  456. }
  457. if ((obj = attributes.get(TextAttribute.TRANSFORM)) != null) {
  458. if (obj instanceof TransformAttribute) {
  459. nonIdentityTx = !((TransformAttribute)obj).isIdentity();
  460. } else if (obj instanceof AffineTransform) {
  461. nonIdentityTx = !((AffineTransform)obj).isIdentity();
  462. }
  463. }
  464. if ((obj = attributes.get(TextAttribute.SUPERSCRIPT)) != null) {
  465. if (obj instanceof Integer) {
  466. superscript = ((Integer)obj).intValue();
  467. nonIdentityTx |= superscript != 0;
  468. }
  469. }
  470. if ((obj = attributes.get(TextAttribute.WIDTH)) != null) {
  471. if (obj instanceof Float) {
  472. width = ((Float)obj).floatValue();
  473. nonIdentityTx |= width != 1;
  474. }
  475. }
  476. }
  477. }
  478. /**
  479. * Returns a <code>Font</code> appropriate to this attribute set.
  480. *
  481. * @param attributes the attributes to assign to the new
  482. * <code>Font</code>
  483. * @return a new <code>Font</code> created with the specified
  484. * attributes
  485. * @since 1.2
  486. * @see java.awt.font.TextAttribute
  487. */
  488. public static Font getFont(Map<? extends Attribute, ?> attributes) {
  489. Font font = (Font)attributes.get(TextAttribute.FONT);
  490. if (font != null) {
  491. return font;
  492. }
  493. return get(new Key(attributes));
  494. }
  495. private static SoftReference cacheRef = new SoftReference(new HashMap());
  496. private static Font get(Key key) {
  497. Font f = null;
  498. Map cache = (Map)cacheRef.get();
  499. if (cache == null) {
  500. cache = new HashMap();
  501. cacheRef = new SoftReference(cache);
  502. } else {
  503. f = (Font)cache.get(key);
  504. }
  505. if (f == null) {
  506. f = new Font(key.attrs);
  507. cache.put(key, f);
  508. }
  509. return f;
  510. }
  511. // ideally we would construct a font directly from a key, and not
  512. // bother to keep the map around for this. That ought to be a bit
  513. // faster than picking out the params from the Map again, but the
  514. // cache ought to hide this overhead, so I'll skip it for now.
  515. private static class Key {
  516. String family = "Dialog"; // defaults chosen to match Font implementation
  517. float weight = 1.0f;
  518. float posture = 0.0f;
  519. float size = 12.0f;
  520. int superscript = 0;
  521. float width = 1.0f;
  522. double[] txdata = null; // identity
  523. Map attrs;
  524. int hashCode = 0;
  525. Key(Map map) {
  526. attrs = map;
  527. Object o = map.get(TextAttribute.FAMILY);
  528. if (o != null) {
  529. family = (String)o;
  530. }
  531. hashCode = family.hashCode();
  532. o = map.get(TextAttribute.WEIGHT);
  533. if (o != null && o != TextAttribute.WEIGHT_REGULAR) {
  534. // ugh, force to the only values we understand
  535. // weight is either bold, or it's not...
  536. float xweight = ((Float)o).floatValue();
  537. if (xweight == TextAttribute.WEIGHT_BOLD.floatValue()) {
  538. weight = xweight;
  539. hashCode = (hashCode << 3) ^ Float.floatToIntBits(weight);
  540. }
  541. }
  542. o = map.get(TextAttribute.POSTURE);
  543. if (o != null && o != TextAttribute.POSTURE_REGULAR) {
  544. // ugh, same problem as with weight
  545. float xposture = ((Float)o).floatValue();
  546. if (xposture == TextAttribute.POSTURE_OBLIQUE.floatValue()) {
  547. posture = xposture;
  548. hashCode = (hashCode << 3) ^ Float.floatToIntBits(posture);
  549. }
  550. }
  551. o = map.get(TextAttribute.SIZE);
  552. if (o != null) {
  553. size = ((Float)o).floatValue();
  554. if (size != 12.0f) {
  555. hashCode = (hashCode << 3) ^ Float.floatToIntBits(size);
  556. }
  557. }
  558. o = map.get(TextAttribute.TRANSFORM);
  559. if (o != null) {
  560. AffineTransform tx = null;
  561. if (o instanceof TransformAttribute) {
  562. TransformAttribute ta = (TransformAttribute)o;
  563. if (!ta.isIdentity()) {
  564. tx = ta.getTransform();
  565. }
  566. } else if (o instanceof AffineTransform) {
  567. AffineTransform at = (AffineTransform)o;
  568. if (!at.isIdentity()) {
  569. tx = at;
  570. }
  571. }
  572. if (tx != null) {
  573. txdata = new double[6];
  574. tx.getMatrix(txdata);
  575. hashCode = (hashCode << 3) ^ new Double(txdata[0]).hashCode();
  576. }
  577. }
  578. o = map.get(TextAttribute.SUPERSCRIPT);
  579. if (o != null) {
  580. if (o instanceof Integer) {
  581. superscript = ((Integer)o).intValue();
  582. hashCode = hashCode << 3 ^ superscript;
  583. }
  584. }
  585. o = map.get(TextAttribute.WIDTH);
  586. if (o != null) {
  587. if (o instanceof Float) {
  588. width = ((Float)o).floatValue();
  589. hashCode = hashCode << 3 ^ Float.floatToIntBits(width);
  590. }
  591. }
  592. }
  593. public int hashCode() {
  594. return hashCode;
  595. }
  596. public boolean equals(Object rhs) {
  597. Key rhskey = (Key)rhs;
  598. if (this.hashCode == rhskey.hashCode &&
  599. this.size == rhskey.size &&
  600. this.weight == rhskey.weight &&
  601. this.posture == rhskey.posture &&
  602. this.superscript == rhskey.superscript &&
  603. this.width == rhskey.width &&
  604. this.family.equals(rhskey.family) &&
  605. ((this.txdata == null) == (rhskey.txdata == null))) {
  606. if (this.txdata != null) {
  607. for (int i = 0; i < this.txdata.length; ++i) {
  608. if (this.txdata[i] != rhskey.txdata[i]) {
  609. return false;
  610. }
  611. }
  612. }
  613. return true;
  614. }
  615. return false;
  616. }
  617. }
  618. /**
  619. * Returns a new <code>Font</code> using the specified font type
  620. * and input data. The new <code>Font</code> is
  621. * created with a point size of 1 and style {@link #PLAIN PLAIN}.
  622. * This base font can then be used with the <code>deriveFont</code>
  623. * methods in this class to derive new <code>Font</code> objects with
  624. * varying sizes, styles, transforms and font features. This
  625. * method does not close the {@link InputStream}.
  626. * @param fontFormat the type of the <code>Font</code>, which is
  627. * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified.
  628. * or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified.
  629. * @param fontStream an <code>InputStream</code> object representing the
  630. * input data for the font.
  631. * @return a new <code>Font</code> created with the specified font type.
  632. * @throws IllegalArgumentException if <code>fontFormat</code> is not
  633. * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
  634. * @throws FontFormatException if the <code>fontStream</code> data does
  635. * not contain the required font tables for the specified format.
  636. * @throws IOException if the <code>fontStream</code>
  637. * cannot be completely read.
  638. * @since 1.3
  639. */
  640. public static Font createFont(int fontFormat, InputStream fontStream)
  641. throws java.awt.FontFormatException, java.io.IOException {
  642. if (fontFormat != Font.TRUETYPE_FONT &&
  643. fontFormat != Font.TYPE1_FONT) {
  644. throw new IllegalArgumentException ("font format not recognized");
  645. }
  646. final InputStream fStream = fontStream;
  647. Object ret = java.security.AccessController.doPrivileged(
  648. new java.security.PrivilegedAction() {
  649. public Object run() {
  650. File tFile = null;
  651. try {
  652. tFile = File.createTempFile("+~JF", ".tmp", null);
  653. tFile.deleteOnExit();
  654. BufferedInputStream inStream =
  655. new BufferedInputStream(fStream);
  656. FileOutputStream outStream = new FileOutputStream(tFile);
  657. int bytesRead = 0;
  658. int bufSize = 8192;
  659. byte [] buf = new byte[bufSize];
  660. while (bytesRead != -1) {
  661. bytesRead = inStream.read(buf, 0, bufSize);
  662. if (bytesRead != -1) {
  663. outStream.write(buf, 0, bytesRead);
  664. }
  665. }
  666. /* don't close the input stream */
  667. outStream.close();
  668. } catch (IOException e) {
  669. return e;
  670. }
  671. return tFile;
  672. }
  673. });
  674. if (ret instanceof File) {
  675. return new Font((File)ret, fontFormat, true);
  676. } else if (ret instanceof IOException) {
  677. throw (IOException)ret;
  678. } else {
  679. throw new FontFormatException("Couldn't access font stream");
  680. }
  681. }
  682. /**
  683. * Returns a new <code>Font</code> using the specified font type
  684. * and the specified font file. The new <code>Font</code> is
  685. * created with a point size of 1 and style {@link #PLAIN PLAIN}.
  686. * This base font can then be used with the <code>deriveFont</code>
  687. * methods in this class to derive new <code>Font</code> objects with
  688. * varying sizes, styles, transforms and font features.
  689. * @param fontFormat the type of the <code>Font</code>, which is
  690. * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is
  691. * specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is
  692. * specified.
  693. * So long as the returned font, or its derived fonts are referenced
  694. * the implementation may continue to access <code>fontFile</code>
  695. * to retrieve font data. Thus the results are undefined if the file
  696. * is changed, or becomes inaccessible.
  697. * @param fontFile a <code>File</code> object representing the
  698. * input data for the font.
  699. * @return a new <code>Font</code> created with the specified font type.
  700. * @throws IllegalArgumentException if <code>fontFormat</code> is not
  701. * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
  702. * @throws NullPointerException if <code>fontFile</code> is null.
  703. * @throws IOException if the <code>fontFile</code> cannot be read.
  704. * @throws FontFormatException if <code>fontFile</code> does
  705. * not contain the required font tables for the specified format.
  706. * @throws SecurityException if the executing code does not have
  707. * permission to read from the file.
  708. * @since 1.5
  709. */
  710. public static Font createFont(int fontFormat, File fontFile)
  711. throws java.awt.FontFormatException, java.io.IOException {
  712. if (fontFormat != Font.TRUETYPE_FONT &&
  713. fontFormat != Font.TYPE1_FONT) {
  714. throw new IllegalArgumentException ("font format not recognized");
  715. }
  716. SecurityManager sm = System.getSecurityManager();
  717. if (sm != null) {
  718. FilePermission filePermission =
  719. new FilePermission(fontFile.getPath(), "read");
  720. sm.checkPermission(filePermission);
  721. }
  722. if (!fontFile.canRead()) {
  723. throw new IOException("Can't read " + fontFile);
  724. }
  725. return new Font(fontFile, fontFormat, false);
  726. }
  727. /**
  728. * Returns a copy of the transform associated with this
  729. * <code>Font</code>.
  730. * @return an {@link AffineTransform} object representing the
  731. * transform attribute of this <code>Font</code> object.
  732. */
  733. public AffineTransform getTransform() {
  734. /* The most common case is the identity transform. Most callers
  735. * should call isTransformed() first, to decide if they need to
  736. * get the transform, but some may not. Here we check to see
  737. * if we have a nonidentity transform, and only do the work to
  738. * fetch and/or compute it if so, otherwise we return a new
  739. * identity transform.
  740. *
  741. * Note that the transform is _not_ necessarily the same as
  742. * the transform passed in as an Attribute in a Map, as the
  743. * transform returned will also reflect the effects of WIDTH and
  744. * SUPERSCRIPT attributes. Clients who want the actual transform
  745. * need to call getRequestedAttributes.
  746. */
  747. if (nonIdentityTx) {
  748. AffineTransform at = null;
  749. Object obj = getRequestedAttributes().get(TextAttribute.TRANSFORM);
  750. if (obj != null) {
  751. if( obj instanceof TransformAttribute ){
  752. at = ((TransformAttribute)obj).getTransform();
  753. }
  754. else {
  755. if ( obj instanceof AffineTransform){
  756. at = new AffineTransform((AffineTransform)obj);
  757. }
  758. }
  759. } else {
  760. at = new AffineTransform();
  761. }
  762. if (superscript != 0) {
  763. // can't get ascent and descent here, recursive call to this fn, so use pointsize
  764. // let users combine super- and sub-scripting
  765. double trans = 0;
  766. int n = 0;
  767. boolean up = superscript > 0;
  768. int sign = up ? -1 : 1;
  769. int ss = up ? superscript : -superscript;
  770. while ((ss & 7) > n) {
  771. int newn = ss & 7;
  772. trans += sign * (ssinfo[newn] - ssinfo[n]);
  773. ss >>= 3;
  774. sign = -sign;
  775. n = newn;
  776. }
  777. trans *= pointSize;
  778. double scale = Math.pow(2./3., n);
  779. at.preConcatenate(AffineTransform.getTranslateInstance(0, trans));
  780. at.scale(scale, scale);
  781. // note on placement and italics
  782. // We preconcatenate the transform because we don't want to translate along
  783. // the italic angle, but purely perpendicular to the baseline. While this
  784. // looks ok for superscripts, it can lead subscripts to stack on each other
  785. // and bring the following text too close. The way we deal with potential
  786. // collisions that can occur in the case of italics is by adjusting the
  787. // horizontal spacing of the adjacent glyphvectors. Examine the italic
  788. // angle of both vectors, if one is non-zero, compute the minimum ascent
  789. // and descent, and then the x position at each for each vector along its
  790. // italic angle starting from its (offset) baseline. Compute the difference
  791. // between the x positions and use the maximum difference to adjust the
  792. // position of the right gv.
  793. }
  794. if (width != 1f) {
  795. at.scale(width, 1f);
  796. }
  797. return at;
  798. }
  799. return new AffineTransform();
  800. }
  801. // x = r^0 + r^1 + r^2... r^n
  802. // rx = r^1 + r^2 + r^3... r^(n+1)
  803. // x - rx = r^0 - r^(n+1)
  804. // x (1 - r) = r^0 - r^(n+1)
  805. // x = (r^0 - r^(n+1)) / (1 - r)
  806. // x = (1 - r^(n+1)) / (1 - r)
  807. // scale ratio is 2/3
  808. // trans = 1/2 of ascent * x
  809. // assume ascent is 3/4 of point size
  810. private static final float[] ssinfo = {
  811. 0.0f,
  812. 0.375f,
  813. 0.625f,
  814. 0.7916667f,
  815. 0.9027778f,
  816. 0.9768519f,
  817. 1.0262346f,
  818. 1.0591564f,
  819. };
  820. /**
  821. * Returns the family name of this <code>Font</code>.
  822. *
  823. * <p>The family name of a font is font specific. Two fonts such as
  824. * Helvetica Italic and Helvetica Bold have the same family name,
  825. * <i>Helvetica</i>, whereas their font face names are
  826. * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of
  827. * available family names may be obtained by using the
  828. * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
  829. *
  830. * <p>Use <code>getName</code> to get the logical name of the font.
  831. * Use <code>getFontName</code> to get the font face name of the font.
  832. * @return a <code>String</code> that is the family name of this
  833. * <code>Font</code>.
  834. *
  835. * @see #getName
  836. * @see #getFontName
  837. * @since JDK1.1
  838. */
  839. public String getFamily() {
  840. return getFamily_NoClientCode();
  841. }
  842. // NOTE: This method is called by privileged threads.
  843. // We implement this functionality in a package-private
  844. // method to insure that it cannot be overridden by client
  845. // subclasses.
  846. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  847. final String getFamily_NoClientCode() {
  848. return getFamily(Locale.getDefault());
  849. }
  850. /**
  851. * Returns the family name of this <code>Font</code>, localized for
  852. * the specified locale.
  853. *
  854. * <p>The family name of a font is font specific. Two fonts such as
  855. * Helvetica Italic and Helvetica Bold have the same family name,
  856. * <i>Helvetica</i>, whereas their font face names are
  857. * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of
  858. * available family names may be obtained by using the
  859. * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
  860. *
  861. * <p>Use <code>getFontName</code> to get the font face name of the font.
  862. * @param l locale for which to get the family name
  863. * @return a <code>String</code> representing the family name of the
  864. * font, localized for the specified locale.
  865. * @see #getFontName
  866. * @see java.util.Locale
  867. * @since 1.2
  868. */
  869. public String getFamily(Locale l) {
  870. if (l == null) {
  871. throw new NullPointerException("null locale doesn't mean default");
  872. }
  873. return getFont2D().getFamilyName(l);
  874. }
  875. /**
  876. * Returns the postscript name of this <code>Font</code>.
  877. * Use <code>getFamily</code> to get the family name of the font.
  878. * Use <code>getFontName</code> to get the font face name of the font.
  879. * @return a <code>String</code> representing the postscript name of
  880. * this <code>Font</code>.
  881. * @since 1.2
  882. */
  883. public String getPSName() {
  884. return getFont2D().getPostscriptName();
  885. }
  886. /**
  887. * Returns the logical name of this <code>Font</code>.
  888. * Use <code>getFamily</code> to get the family name of the font.
  889. * Use <code>getFontName</code> to get the font face name of the font.
  890. * @return a <code>String</code> representing the logical name of
  891. * this <code>Font</code>.
  892. * @see #getFamily
  893. * @see #getFontName
  894. * @since JDK1.0
  895. */
  896. public String getName() {
  897. return name;
  898. }
  899. /**
  900. * Returns the font face name of this <code>Font</code>. For example,
  901. * Helvetica Bold could be returned as a font face name.
  902. * Use <code>getFamily</code> to get the family name of the font.
  903. * Use <code>getName</code> to get the logical name of the font.
  904. * @return a <code>String</code> representing the font face name of
  905. * this <code>Font</code>.
  906. * @see #getFamily
  907. * @see #getName
  908. * @since 1.2
  909. */
  910. public String getFontName() {
  911. return getFontName(Locale.getDefault());
  912. }
  913. /**
  914. * Returns the font face name of the <code>Font</code>, localized
  915. * for the specified locale. For example, Helvetica Fett could be
  916. * returned as the font face name.
  917. * Use <code>getFamily</code> to get the family name of the font.
  918. * @param l a locale for which to get the font face name
  919. * @return a <code>String</code> representing the font face name,
  920. * localized for the specified locale.
  921. * @see #getFamily
  922. * @see java.util.Locale
  923. */
  924. public String getFontName(Locale l) {
  925. if (l == null) {
  926. throw new NullPointerException("null locale doesn't mean default");
  927. }
  928. return getFont2D().getFontName(l);
  929. }
  930. /**
  931. * Returns the style of this <code>Font</code>. The style can be
  932. * PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
  933. * @return the style of this <code>Font</code>
  934. * @see #isPlain
  935. * @see #isBold
  936. * @see #isItalic
  937. * @since JDK1.0
  938. */
  939. public int getStyle() {
  940. return style;
  941. }
  942. /**
  943. * Returns the point size of this <code>Font</code>, rounded to
  944. * an integer.
  945. * Most users are familiar with the idea of using <i>point size</i> to
  946. * specify the size of glyphs in a font. This point size defines a
  947. * measurement between the baseline of one line to the baseline of the
  948. * following line in a single spaced text document. The point size is
  949. * based on <i>typographic points</i>, approximately 1/72 of an inch.
  950. * <p>
  951. * The Java(tm)2D API adopts the convention that one point is
  952. * equivalent to one unit in user coordinates. When using a
  953. * normalized transform for converting user space coordinates to
  954. * device space coordinates 72 user
  955. * space units equal 1 inch in device space. In this case one point
  956. * is 1/72 of an inch.
  957. * @return the point size of this <code>Font</code> in 1/72 of an
  958. * inch units.
  959. * @see #getSize2D
  960. * @see GraphicsConfiguration#getDefaultTransform
  961. * @see GraphicsConfiguration#getNormalizingTransform
  962. * @since JDK1.0
  963. */
  964. public int getSize() {
  965. return size;
  966. }
  967. /**
  968. * Returns the point size of this <code>Font</code> in
  969. * <code>float</code> value.
  970. * @return the point size of this <code>Font</code> as a
  971. * <code>float</code> value.
  972. * @see #getSize
  973. * @since 1.2
  974. */
  975. public float getSize2D() {
  976. return pointSize;
  977. }
  978. /**
  979. * Indicates whether or not this <code>Font</code> object's style is
  980. * PLAIN.
  981. * @return <code>true</code> if this <code>Font</code> has a
  982. * PLAIN sytle;
  983. * <code>false</code> otherwise.
  984. * @see java.awt.Font#getStyle
  985. * @since JDK1.0
  986. */
  987. public boolean isPlain() {
  988. return style == 0;
  989. }
  990. /**
  991. * Indicates whether or not this <code>Font</code> object's style is
  992. * BOLD.
  993. * @return <code>true</code> if this <code>Font</code> object's
  994. * style is BOLD;
  995. * <code>false</code> otherwise.
  996. * @see java.awt.Font#getStyle
  997. * @since JDK1.0
  998. */
  999. public boolean isBold() {
  1000. return (style & BOLD) != 0;
  1001. }
  1002. /**
  1003. * Indicates whether or not this <code>Font</code> object's style is
  1004. * ITALIC.
  1005. * @return <code>true</code> if this <code>Font</code> object's
  1006. * style is ITALIC;
  1007. * <code>false</code> otherwise.
  1008. * @see java.awt.Font#getStyle
  1009. * @since JDK1.0
  1010. */
  1011. public boolean isItalic() {
  1012. return (style & ITALIC) != 0;
  1013. }
  1014. /**
  1015. * Indicates whether or not this <code>Font</code> object has a
  1016. * transform that affects its size in addition to the Size
  1017. * attribute.
  1018. * @return <code>true</code> if this <code>Font</code> object
  1019. * has a non-identity AffineTransform attribute.
  1020. * <code>false</code> otherwise.
  1021. * @see java.awt.Font#getTransform
  1022. * @since 1.4
  1023. */
  1024. public boolean isTransformed() {
  1025. return nonIdentityTx;
  1026. }
  1027. /**
  1028. * Returns a <code>Font</code> object from the system properties list.
  1029. * <code>nm</code> is treated as the name of a system property to be
  1030. * obtained. The <code>String</code> value of this property is then
  1031. * interpreted as a <code>Font</code> object according to the
  1032. * specification of <code>Font.decode(String)</code>
  1033. * If the specified property is not found, null is returned instead.
  1034. *
  1035. * @param nm the property name
  1036. * @return a <code>Font</code> object that the property name
  1037. * describes, or null if no such property exists.
  1038. * @throws NullPointerException if nm is null.
  1039. * @since 1.2
  1040. * @see #decode(String)
  1041. */
  1042. public static Font getFont(String nm) {
  1043. return getFont(nm, null);
  1044. }
  1045. /**
  1046. * Returns the <code>Font</code> that the <code>str</code>
  1047. * argument describes.
  1048. * To ensure that this method returns the desired Font,
  1049. * format the <code>str</code> parameter in
  1050. * one of these ways
  1051. * <p>
  1052. * <ul>
  1053. * <li><em>fontname-style-pointsize</em>
  1054. * <li><em>fontname-pointsize</em>
  1055. * <li><em>fontname-style</em>
  1056. * <li><em>fontname</em>
  1057. * <li><em>fontname style pointsize</em>
  1058. * <li><em>fontname pointsize</em>
  1059. * <li><em>fontname style</em>
  1060. * <li><em>fontname</em>
  1061. * </ul>
  1062. * in which <i>style</i> is one of the four
  1063. * case-insensitive strings:
  1064. * <code>"PLAIN"</code>, <code>"BOLD"</code>, <code>"BOLDITALIC"</code>, or
  1065. * <code>"ITALIC"</code>, and pointsize is a positive decimal integer
  1066. * representation of the point size.
  1067. * For example, if you want a font that is Arial, bold, with
  1068. * a point size of 18, you would call this method with:
  1069. * "Arial-BOLD-18".
  1070. * This is equivalent to calling the Font constructor :
  1071. * <code>new Font("Arial", Font.BOLD, 18);</code>
  1072. * and the values are interpreted as specified by that constructor.
  1073. * <p>
  1074. * A valid trailing decimal field is always interpreted as the pointsize.
  1075. * Therefore a fontname containing a trailing decimal value should not
  1076. * be used in the fontname only form.
  1077. * <p>
  1078. * If a style name field is not one of the valid style strings, it is
  1079. * interpreted as part of the font name, and the default style is used.
  1080. * <p>
  1081. * Only one of ' ' or '-' may be used to separate fields in the input.
  1082. * The identified separator is the one closest to the end of the string
  1083. * which separates a valid pointsize, or a valid style name from
  1084. * the rest of the string.
  1085. * Null (empty) pointsize and style fields are treated
  1086. * as valid fields with the default value for that field.
  1087. *<p>
  1088. * Some font names may include the separator characters ' ' or '-'.
  1089. * If <code>str</code> is not formed with 3 components, e.g. such that
  1090. * <code>style</code> or <code>pointsize</code> fields are not present in
  1091. * <code>str</code>, and <code>fontname</code> also contains a
  1092. * character determined to be the separator character
  1093. * then these characters where they appear as intended to be part of
  1094. * <code>fontname</code> may instead be interpreted as separators
  1095. * so the font name may not be properly recognised.
  1096. *
  1097. * <p>
  1098. * The default size is 12 and the default style is PLAIN.
  1099. * If <code>str</code> does not specify a valid size, the returned
  1100. * <code>Font</code> has a size of 12. If <code>str</code> does not
  1101. * specify a valid style, the returned Font has a style of PLAIN.
  1102. * If you do not specify a valid font name in
  1103. * the <code>str</code> argument, this method will return
  1104. * a font with the family name "Dialog".
  1105. * To determine what font family names are available on
  1106. * your system, use the
  1107. * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
  1108. * If <code>str</code> is <code>null</code>, a new <code>Font</code>
  1109. * is returned with the family name "Dialog", a size of 12 and a
  1110. * PLAIN style.
  1111. * @param str the name of the font, or <code>null</code>
  1112. * @return the <code>Font</code> object that <code>str</code>
  1113. * describes, or a new default <code>Font</code> if
  1114. * <code>str</code> is <code>null</code>.
  1115. * @see #getFamily
  1116. * @since JDK1.1
  1117. */
  1118. public static Font decode(String str) {
  1119. String fontName = str;
  1120. String styleName = "";
  1121. int fontSize = 12;
  1122. int fontStyle = Font.PLAIN;
  1123. if (str == null) {
  1124. return new Font("Dialog", fontStyle, fontSize);
  1125. }
  1126. int lastHyphen = str.lastIndexOf('-');
  1127. int lastSpace = str.lastIndexOf(' ');
  1128. char sepChar = (lastHyphen > lastSpace) ? '-' : ' ';
  1129. int sizeIndex = str.lastIndexOf(sepChar);
  1130. int styleIndex = str.lastIndexOf(sepChar, sizeIndex-1);
  1131. int strlen = str.length();
  1132. if (sizeIndex > 0 && sizeIndex+1 < strlen) {
  1133. try {
  1134. fontSize =
  1135. Integer.valueOf(str.substring(sizeIndex+1)).intValue();
  1136. if (fontSize <= 0) {
  1137. fontSize = 12;
  1138. }
  1139. } catch (NumberFormatException e) {
  1140. /* It wasn't a valid size, if we didn't also find the
  1141. * start of the style string perhaps this is the style */
  1142. styleIndex = sizeIndex;
  1143. sizeIndex = strlen;
  1144. if (str.charAt(sizeIndex-1) == sepChar) {
  1145. sizeIndex--;
  1146. }
  1147. }
  1148. }
  1149. if (styleIndex >= 0 && styleIndex+1 < strlen) {
  1150. styleName = str.substring(styleIndex+1, sizeIndex);
  1151. styleName = styleName.toLowerCase(Locale.ENGLISH);
  1152. if (styleName.equals("bolditalic")) {
  1153. fontStyle = Font.BOLD | Font.ITALIC;
  1154. } else if (styleName.equals("italic")) {
  1155. fontStyle = Font.ITALIC;
  1156. } else if (styleName.equals("bold")) {
  1157. fontStyle = Font.BOLD;
  1158. } else if (styleName.equals("plain")) {
  1159. fontStyle = Font.PLAIN;
  1160. } else {
  1161. /* this string isn't any of the expected styles, so
  1162. * assume its part of the font name
  1163. */
  1164. styleIndex = sizeIndex;
  1165. if (str.charAt(styleIndex-1) == sepChar) {
  1166. styleIndex--;
  1167. }
  1168. }
  1169. fontName = str.substring(0, styleIndex);
  1170. } else {
  1171. int fontEnd = strlen;
  1172. if (styleIndex > 0) {
  1173. fontEnd = styleIndex;
  1174. } else if (sizeIndex > 0) {
  1175. fontEnd = sizeIndex;
  1176. }
  1177. if (fontEnd > 0 && str.charAt(fontEnd-1) == sepChar) {
  1178. fontEnd--;
  1179. }
  1180. fontName = str.substring(0, fontEnd);
  1181. }
  1182. return new Font(fontName, fontStyle, fontSize);
  1183. }
  1184. /**
  1185. * Gets the specified <code>Font</code> from the system properties
  1186. * list. As in the <code>getProperty</code> method of
  1187. * <code>System</code>, the first
  1188. * argument is treated as the name of a system property to be
  1189. * obtained. The <code>String</code> value of this property is then
  1190. * interpreted as a <code>Font</code> object.
  1191. * <p>
  1192. * The property value should be one of the forms accepted by
  1193. * <code>Font.decode(String)</code>
  1194. * If the specified property is not found, the <code>font</code>
  1195. * argument is returned instead.
  1196. * @param nm the case-insensitive property name
  1197. * @param font a default <code>Font</code> to return if property
  1198. * <code>nm</code> is not defined
  1199. * @return the <code>Font</code> value of the property.
  1200. * @throws NullPointerException if nm is null.
  1201. * @see #decode(String)
  1202. */
  1203. public static Font getFont(String nm, Font font) {
  1204. String str = null;
  1205. try {
  1206. str =System.getProperty(nm);
  1207. } catch(SecurityException e) {
  1208. }
  1209. if (str == null) {
  1210. return font;
  1211. }
  1212. return decode ( str );
  1213. }
  1214. /**
  1215. * Returns a hashcode for this <code>Font</code>.
  1216. * @return a hashcode value for this <code>Font</code>.
  1217. * @since JDK1.0
  1218. */
  1219. public int hashCode() {
  1220. return name.hashCode() ^ style ^ size;
  1221. }
  1222. /**
  1223. * Compares this <code>Font</code> object to the specified
  1224. * <code>Object</code>.
  1225. * @param obj the <code>Object</code> to compare
  1226. * @return <code>true</code> if the objects are the same
  1227. * or if the argument is a <code>Font</code> object
  1228. * describing the same font as this object;
  1229. * <code>false</code> otherwise.
  1230. * @since JDK1.0
  1231. */
  1232. public boolean equals(Object obj) {
  1233. if (obj == this) {
  1234. return true;
  1235. }
  1236. if (obj != null) {
  1237. try {
  1238. Font font = (Font)obj;
  1239. if ((size == font.size) &&
  1240. (pointSize == font.pointSize) &&
  1241. (style == font.style) &&
  1242. (superscript == font.superscript) &&
  1243. (width == font.width) &&
  1244. name.equals(font.name)) {
  1245. double[] thismat = this.getMatrix();
  1246. double[] thatmat = font.getMatrix();
  1247. return thismat[0] == thatmat[0]
  1248. && thismat[1] == thatmat[1]
  1249. && thismat[2] == thatmat[2]
  1250. && thismat[3] == thatmat[3]
  1251. && thismat[4] == thatmat[4]
  1252. && thismat[5] == thatmat[5];
  1253. }
  1254. }
  1255. catch (ClassCastException e) {
  1256. }
  1257. }
  1258. return false;
  1259. }
  1260. /**
  1261. * Converts this <code>Font</code> object to a <code>String</code>
  1262. * representation.
  1263. * @return a <code>String</code> representation of this
  1264. * <code>Font</code> object.
  1265. * @since JDK1.0
  1266. */
  1267. // NOTE: This method may be called by privileged threads.
  1268. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  1269. public String toString() {
  1270. String strStyle;
  1271. if (isBold()) {
  1272. strStyle = isItalic() ? "bolditalic" : "bold";
  1273. } else {
  1274. strStyle = isItalic() ? "italic" : "plain";
  1275. }
  1276. return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" +
  1277. strStyle + ",size=" + size + "]";
  1278. } // toString()
  1279. /** Serialization support. A <code>readObject</code>
  1280. * method is neccessary because the constructor creates
  1281. * the font's peer, and we can't serialize the peer.
  1282. * Similarly the computed font "family" may be different
  1283. * at <code>readObject</code> time than at
  1284. * <code>writeObject</code> time. An integer version is
  1285. * written so that future versions of this class will be
  1286. * able to recognize serialized output from this one.
  1287. */
  1288. /**
  1289. * The <code>Font</code> Serializable Data Form.
  1290. *
  1291. * @serial
  1292. */
  1293. private int fontSerializedDataVersion = 1;
  1294. /**
  1295. * Writes default serializable fields to a stream.
  1296. *
  1297. * @param s the <code>ObjectOutputStream</code> to write
  1298. * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
  1299. * @see #readObject(java.io.ObjectInputStream)
  1300. */
  1301. private void writeObject(java.io.ObjectOutputStream s)
  1302. throws java.lang.ClassNotFoundException,
  1303. java.io.IOException
  1304. {
  1305. s.defaultWriteObject();
  1306. }
  1307. /**
  1308. * Reads the <code>ObjectInputStream</code>.
  1309. * Unrecognized keys or values will be ignored.
  1310. *
  1311. * @param s the <code>ObjectInputStream</code> to read
  1312. * @serial
  1313. * @see #writeObject(java.io.ObjectOutputStream)
  1314. */
  1315. private void readObject(java.io.ObjectInputStream s)
  1316. throws java.lang.ClassNotFoundException,
  1317. java.io.IOException
  1318. {
  1319. s.defaultReadObject();
  1320. if (pointSize == 0) {
  1321. pointSize = (float)size;
  1322. }
  1323. width = 1f; // init transient field
  1324. initializeFont(fRequestedAttributes);
  1325. }
  1326. /**
  1327. * Returns the number of glyphs in this <code>Font</code>. Glyph codes
  1328. * for this <code>Font</code> range from 0 to
  1329. * <code>getNumGlyphs()</code> - 1.
  1330. * @return the number of glyphs in this <code>Font</code>.
  1331. * @since 1.2
  1332. */
  1333. public int getNumGlyphs() {
  1334. return getFont2D().getNumGlyphs();
  1335. }
  1336. /**
  1337. * Returns the glyphCode which is used when this <code>Font</code>
  1338. * does not have a glyph for a specified unicode.
  1339. * @return the glyphCode of this <code>Font</code>.
  1340. * @since 1.2
  1341. */
  1342. public int getMissingGlyphCode() {
  1343. return getFont2D().getMissingGlyphCode();
  1344. }
  1345. /**
  1346. * get the transform matrix for this font.
  1347. */
  1348. /* for identity transforms this code attempts to share a matrix
  1349. * amongst fonts with the same pt size */
  1350. private static double cachedMat[];
  1351. private double[] getMatrix() {
  1352. if (matrix == null) {
  1353. double ptSize = this.getSize2D();
  1354. if (nonIdentityTx) {
  1355. AffineTransform tx = getTransform();
  1356. tx.scale(ptSize, ptSize);
  1357. tx.getMatrix(matrix = new double[6]);
  1358. } else {
  1359. synchronized (Font.class) {
  1360. double[] m = cachedMat;
  1361. if (m == null || m[0] != ptSize) {
  1362. cachedMat = m =
  1363. new double[] {ptSize, 0, 0, ptSize, 0, 0 };
  1364. }
  1365. matrix = m;
  1366. }
  1367. }
  1368. }
  1369. return matrix;
  1370. }
  1371. /**
  1372. * Returns the baseline appropriate for displaying this character.
  1373. * <p>
  1374. * Large fonts can support different writing systems, and each system can
  1375. * use a different baseline.
  1376. * The character argument determines the writing system to use. Clients
  1377. * should not assume all characters use the same baseline.
  1378. *
  1379. * @param c a character used to identify the writing system
  1380. * @return the baseline appropriate for the specified character.
  1381. * @see LineMetrics#getBaselineOffsets
  1382. * @see #ROMAN_BASELINE
  1383. * @see #CENTER_BASELINE
  1384. * @see #HANGING_BASELINE
  1385. * @since 1.2
  1386. */
  1387. public byte getBaselineFor(char c) {
  1388. return getFont2D().getBaselineFor(c);
  1389. }
  1390. /**
  1391. * Returns a map of font attributes available in this
  1392. * <code>Font</code>. Attributes include things like ligatures and
  1393. * glyph substitution.
  1394. * @return the attributes map of this <code>Font</code>.
  1395. */
  1396. public Map<TextAttribute,?> getAttributes(){
  1397. return (Map<TextAttribute,?>)getRequestedAttributes().clone();
  1398. }
  1399. /**
  1400. * Returns the keys of all the attributes supported by this
  1401. * <code>Font</code>. These attributes can be used to derive other
  1402. * fonts.
  1403. * @return an array containing the keys of all the attributes
  1404. * supported by this <code>Font</code>.
  1405. * @since 1.2
  1406. */
  1407. public Attribute[] getAvailableAttributes(){
  1408. Attribute attributes[] = {
  1409. TextAttribute.FAMILY,
  1410. TextAttribute.WEIGHT,
  1411. TextAttribute.POSTURE,
  1412. TextAttribute.SIZE,
  1413. TextAttribute.TRANSFORM,
  1414. TextAttribute.SUPERSCRIPT,
  1415. TextAttribute.WIDTH,
  1416. };
  1417. return attributes;
  1418. }
  1419. /**
  1420. * Creates a new <code>Font</code> object by replicating this
  1421. * <code>Font</code> object and applying a new style and size.
  1422. * @param style the style for the new <code>Font</code>
  1423. * @param size the size for the new <code>Font</code>
  1424. * @return a new <code>Font</code> object.
  1425. * @since 1.2
  1426. */
  1427. public Font deriveFont(int style, float size){
  1428. Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone();
  1429. applyStyle(style, newAttributes);
  1430. applySize(size, newAttributes);
  1431. return new Font(newAttributes, createdFont, font2DHandle);
  1432. }
  1433. /**
  1434. * Creates a new <code>Font</code> object by replicating this
  1435. * <code>Font</code> object and applying a new style and transform.
  1436. * @param style the style for the new <code>Font</code>
  1437. * @param trans the <code>AffineTransform</code> associated with the
  1438. * new <code>Font</code>
  1439. * @return a new <code>Font</code> object.
  1440. * @throws IllegalArgumentException if <code>trans</code> is
  1441. * <code>null</code>
  1442. * @since 1.2
  1443. */
  1444. public Font deriveFont(int style, AffineTransform trans){
  1445. Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone();
  1446. applyStyle(style, newAttributes);
  1447. applyTransform(trans, newAttributes);
  1448. return new Font(newAttributes, createdFont, font2DHandle);
  1449. }
  1450. /**
  1451. * Creates a new <code>Font</code> object by replicating the current
  1452. * <code>Font</code> object and applying a new size to it.
  1453. * @param size the size for the new <code>Font</code>.
  1454. * @return a new <code>Font</code> object.
  1455. * @since 1.2
  1456. */
  1457. public Font deriveFont(float size){
  1458. Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone();
  1459. applySize(size, newAttributes);
  1460. return new Font(newAttributes, createdFont, font2DHandle);
  1461. }
  1462. /**
  1463. * Creates a new <code>Font</code> object by replicating the current
  1464. * <code>Font</code> object and applying a new transform to it.
  1465. * @param trans the <code>AffineTransform</code> associated with the
  1466. * new <code>Font</code>
  1467. * @return a new <code>Font</code> object.
  1468. * @throws IllegalArgumentException if <code>trans</code> is
  1469. * <code>null</code>
  1470. * @since 1.2
  1471. */
  1472. public Font deriveFont(AffineTransform trans){
  1473. Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone();
  1474. applyTransform(trans, newAttributes);
  1475. return new Font(newAttributes, createdFont, font2DHandle);
  1476. }
  1477. /**
  1478. * Creates a new <code>Font</code> object by replicating the current
  1479. * <code>Font</code> object and applying a new style to it.
  1480. * @param style the style for the new <code>Font</code>
  1481. * @return a new <code>Font</code> object.
  1482. * @since 1.2
  1483. */
  1484. public Font deriveFont(int style){
  1485. Hashtable newAttributes = (Hashtable)getRequestedAttributes().clone();
  1486. applyStyle(style, newAttributes);
  1487. return new Font(newAttributes, createdFont, font2DHandle);
  1488. }
  1489. /**
  1490. * Creates a new <code>Font</code> object by replicating the current
  1491. * <code>Font</code> object and applying a new set of font attributes
  1492. * to it.
  1493. * @param attributes a map of attributes enabled for the new
  1494. * <code>Font</code>
  1495. * @return a new <code>Font</code> object.
  1496. * @since 1.2
  1497. */
  1498. public Font deriveFont(Map<? extends Attribute, ?> attributes) {
  1499. if (attributes == null || attributes.size() == 0) {
  1500. return this;
  1501. }
  1502. Hashtable newAttrs = new Hashtable(getAttributes());
  1503. Attribute validAttribs[] = getAvailableAttributes();
  1504. Object obj;
  1505. for(int i = 0; i < validAttribs.length; i++){
  1506. if ((obj = attributes.get(validAttribs[i])) != null) {
  1507. newAttrs.put(validAttribs[i],obj);
  1508. }
  1509. }
  1510. return new Font(newAttrs, createdFont, font2DHandle);
  1511. }
  1512. /**
  1513. * Checks if this <code>Font</code> has a glyph for the specified
  1514. * character.
  1515. *
  1516. * <p> <b>Note:</b> This method cannot handle <a
  1517. * href="../../java/lang/Character.html#supplementary"> supplementary
  1518. * characters</a>. To support all Unicode characters, including
  1519. * supplementary characters, use the {@link #canDisplay(int)}
  1520. * method or <code>canDisplayUpTo</code> methods.
  1521. *
  1522. * @param c the character for which a glyph is needed
  1523. * @return <code>true</code> if this <code>Font</code> has a glyph for this
  1524. * character; <code>false</code> otherwise.
  1525. * @since 1.2
  1526. */
  1527. public boolean canDisplay(char c){
  1528. return getFont2D().canDisplay(c);
  1529. }
  1530. /**
  1531. * Checks if this <code>Font</code> has a glyph for the specified
  1532. * character.
  1533. *
  1534. * @param codePoint the character (Unicode code point) for which a glyph
  1535. * is needed.
  1536. * @return <code>true</code> if this <code>Font</code> has a glyph for the
  1537. * character; <code>false</code> otherwise.
  1538. * @throws IllegalArgumentException if the code point is not a valid Unicode
  1539. * code point.
  1540. * @see Character#isValidCodePoint(int)
  1541. * @since 1.5
  1542. */
  1543. public boolean canDisplay(int codePoint) {
  1544. if (!Character.isValidCodePoint(codePoint)) {
  1545. throw new IllegalArgumentException("invalid code point: " + Integer.toHexString(codePoint));
  1546. }
  1547. return getFont2D().canDisplay(codePoint);
  1548. }
  1549. /**
  1550. * Indicates whether or not this <code>Font</code> can display a
  1551. * specified <code>String</code>. For strings with Unicode encoding,
  1552. * it is important to know if a particular font can display the
  1553. * string. This method returns an offset into the <code>String</code>
  1554. * <code>str</code> which is the first character this
  1555. * <code>Font</code> cannot display without using the missing glyph
  1556. * code. If the <code>Font</code> can display all characters, -1 is
  1557. * returned.
  1558. * @param str a <code>String</code> object
  1559. * @return an offset into <code>str</code> that points
  1560. * to the first character in <code>str</code> that this
  1561. * <code>Font</code> cannot display; or <code>-1</code> if
  1562. * this <code>Font</code> can display all characters in
  1563. * <code>str</code>.
  1564. * @since 1.2
  1565. */
  1566. public int canDisplayUpTo(String str) {
  1567. return canDisplayUpTo(new StringCharacterIterator(str), 0,
  1568. str.length());
  1569. }
  1570. /**
  1571. * Indicates whether or not this <code>Font</code> can display
  1572. * the characters in the specified <code>text</code>
  1573. * starting at <code>start</code> and ending at
  1574. * <code>limit</code>. This method is a convenience overload.
  1575. * @param text the specified array of <code>char</code> values
  1576. * @param start the specified starting offset (in
  1577. * <code>char</code>s) into the specified array of
  1578. * <code>char</code> values
  1579. * @param limit the specified ending offset (in
  1580. * <code>char</code>s) into the specified array of
  1581. * <code>char</code> values
  1582. * @return an offset into <code>text</code> that points
  1583. * to the first character in <code>text</code> that this
  1584. * <code>Font</code> cannot display; or <code>-1</code> if
  1585. * this <code>Font</code> can display all characters in
  1586. * <code>text</code>.
  1587. * @since 1.2
  1588. */
  1589. public int canDisplayUpTo(char[] text, int start, int limit) {
  1590. while (start < limit && canDisplay(text[start])) {
  1591. ++start;
  1592. }
  1593. return start == limit ? -1 : start;
  1594. }
  1595. /**
  1596. * Indicates whether or not this <code>Font</code> can display the
  1597. * text specified by the <code>iter</code> starting at
  1598. * <code>start</code> and ending at <code>limit</code>.
  1599. *
  1600. * @param iter a {@link CharacterIterator} object
  1601. * @param start the specified starting offset into the specified
  1602. * <code>CharacterIterator</code>.
  1603. * @param limit the specified ending offset into the specified
  1604. * <code>CharacterIterator</code>.
  1605. * @return an offset into <code>iter</code> that points
  1606. * to the first character in <code>iter</code> that this
  1607. * <code>Font</code> cannot display; or <code>-1</code> if
  1608. * this <code>Font</code> can display all characters in
  1609. * <code>iter</code>.
  1610. * @since 1.2
  1611. */
  1612. public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
  1613. for (char c = iter.setIndex(start);
  1614. iter.getIndex() < limit && canDisplay(c);
  1615. c = iter.next()) {
  1616. }
  1617. int result = iter.getIndex();
  1618. return result == limit ? -1 : result;
  1619. }
  1620. /**
  1621. * Returns the italic angle of this <code>Font</code>. The italic angle
  1622. * is the inverse slope of the caret which best matches the posture of this
  1623. * <code>Font</code>.
  1624. * @see TextAttribute#POSTURE
  1625. * @return the angle of the ITALIC style of this <code>Font</code>.
  1626. */
  1627. public float getItalicAngle() {
  1628. AffineTransform at = (isTransformed()) ? getTransform() : identityTx;
  1629. return getFont2D().getItalicAngle(this, at, false, false);
  1630. }
  1631. /**
  1632. * Checks whether or not this <code>Font</code> has uniform
  1633. * line metrics. A logical <code>Font</code> might be a
  1634. * composite font, which means that it is composed of different
  1635. * physical fonts to cover different code ranges. Each of these
  1636. * fonts might have different <code>LineMetrics</code>. If the
  1637. * logical <code>Font</code> is a single
  1638. * font then the metrics would be uniform.
  1639. * @return <code>true</code> if this <code>Font</code> has
  1640. * uniform line metrics; <code>false</code> otherwise.
  1641. */
  1642. public boolean hasUniformLineMetrics() {
  1643. return false; // REMIND always safe, but prevents caller optimize
  1644. }
  1645. private transient SoftReference flmref;
  1646. private FontLineMetrics defaultLineMetrics(FontRenderContext frc) {
  1647. FontLineMetrics flm = null;
  1648. if (flmref == null
  1649. || (flm = (FontLineMetrics)flmref.get()) == null
  1650. || !flm.frc.equals(frc)) {
  1651. /* The device transform in the frc is not used in obtaining line
  1652. * metrics, although it probably should be: REMIND find why not?
  1653. * The font transform is used but its applied in getFontMetrics, so
  1654. * just pass identity here
  1655. */
  1656. float [] metrics = new float[4];
  1657. getFont2D().getFontMetrics(this, identityTx,
  1658. frc.isAntiAliased(),
  1659. frc.usesFractionalMetrics(),
  1660. metrics);
  1661. float ascent = metrics[0];
  1662. float descent = metrics[1];
  1663. float leading = metrics[2];
  1664. float ssOffset = 0;
  1665. if (superscript != 0) {
  1666. ssOffset = (float)getTransform().getTranslateY();
  1667. ascent -= ssOffset;
  1668. descent += ssOffset;
  1669. }
  1670. float height = ascent + descent + leading;
  1671. int baselineIndex = 0; // need real index, assumes roman for everything
  1672. float[] baselineOffsets = { 0, (descent2f - ascent) / 2f, -ascent }; // need real baselines eventually
  1673. // !!! desperately need real data here
  1674. float strikethroughOffset = ssOffset -(metrics[0] / 2.5f);
  1675. float strikethroughThickness = (float)(Math.log(pointSize / 4));
  1676. float underlineOffset = ssOffset + strikethroughThickness / 1.5f;
  1677. float underlineThickness = strikethroughThickness;
  1678. float italicAngle = getItalicAngle();
  1679. CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height,
  1680. baselineIndex, baselineOffsets,
  1681. strikethroughOffset, strikethroughThickness,
  1682. underlineOffset, underlineThickness,
  1683. ssOffset, italicAngle);
  1684. flm = new FontLineMetrics(0, cm, frc);
  1685. flmref = new SoftReference(flm);
  1686. }
  1687. return (FontLineMetrics)flm.clone();
  1688. }
  1689. /**
  1690. * Returns a {@link LineMetrics} object created with the specified
  1691. * <code>String</code> and {@link FontRenderContext}.
  1692. * @param str the specified <code>String</code>
  1693. * @param frc the specified <code>FontRenderContext</code>
  1694. * @return a <code>LineMetrics</code> object created with the
  1695. * specified <code>String</code> and {@link FontRenderContext}.
  1696. */
  1697. public LineMetrics getLineMetrics( String str, FontRenderContext frc) {
  1698. FontLineMetrics flm = defaultLineMetrics(frc);
  1699. flm.numchars = str.length();
  1700. return flm;
  1701. }
  1702. /**
  1703. * Returns a <code>LineMetrics</code> object created with the
  1704. * specified arguments.
  1705. * @param str the specified <code>String</code>
  1706. * @param beginIndex the initial offset of <code>str</code>
  1707. * @param limit the end offset of <code>str</code>
  1708. * @param frc the specified <code>FontRenderContext</code>
  1709. * @return a <code>LineMetrics</code> object created with the
  1710. * specified arguments.
  1711. */
  1712. public LineMetrics getLineMetrics( String str,
  1713. int beginIndex, int limit,
  1714. FontRenderContext frc) {
  1715. FontLineMetrics flm = defaultLineMetrics(frc);
  1716. int numChars = limit - beginIndex;
  1717. flm.numchars = (numChars < 0)? 0: numChars;
  1718. return flm;
  1719. }
  1720. /**
  1721. * Returns a <code>LineMetrics</code> object created with the
  1722. * specified arguments.
  1723. * @param chars an array of characters
  1724. * @param beginIndex the initial offset of <code>chars</code>
  1725. * @param limit the end offset of <code>chars</code>
  1726. * @param frc the specified <code>FontRenderContext</code>
  1727. * @return a <code>LineMetrics</code> object created with the
  1728. * specified arguments.
  1729. */
  1730. public LineMetrics getLineMetrics(char [] chars,
  1731. int beginIndex, int limit,
  1732. FontRenderContext frc) {
  1733. FontLineMetrics flm = defaultLineMetrics(frc);
  1734. int numChars = limit - beginIndex;
  1735. flm.numchars = (numChars < 0)? 0: numChars;
  1736. return flm;
  1737. }
  1738. /**
  1739. * Returns a <code>LineMetrics</code> object created with the
  1740. * specified arguments.
  1741. * @param ci the specified <code>CharacterIterator</code>
  1742. * @param beginIndex the initial offset in <code>ci</code>
  1743. * @param limit the end offset of <code>ci</code>
  1744. * @param frc the specified <code>FontRenderContext</code>
  1745. * @return a <code>LineMetrics</code> object created with the
  1746. * specified arguments.
  1747. */
  1748. public LineMetrics getLineMetrics(CharacterIterator ci,
  1749. int beginIndex, int limit,
  1750. FontRenderContext frc) {
  1751. FontLineMetrics flm = defaultLineMetrics(frc);
  1752. int numChars = limit - beginIndex;
  1753. flm.numchars = (numChars < 0)? 0: numChars;
  1754. return flm;
  1755. }
  1756. /**
  1757. * Returns the logical bounds of the specified <code>String</code> in
  1758. * the specified <code>FontRenderContext</code>. The logical bounds
  1759. * contains the origin, ascent, advance, and height, which includes
  1760. * the leading. The logical bounds does not always enclose all the
  1761. * text. For example, in some languages and in some fonts, accent
  1762. * marks can be positioned above the ascent or below the descent.
  1763. * To obtain a visual bounding box, which encloses all the text,
  1764. * use the {@link TextLayout#getBounds() getBounds} method of
  1765. * <code>TextLayout</code>.
  1766. * @param str the specified <code>String</code>
  1767. * @param frc the specified <code>FontRenderContext</code>
  1768. * @return a {@link Rectangle2D} that is the bounding box of the
  1769. * specified <code>String</code> in the specified
  1770. * <code>FontRenderContext</code>.
  1771. * @see FontRenderContext
  1772. * @see Font#createGlyphVector
  1773. * @since 1.2
  1774. */
  1775. public Rectangle2D getStringBounds( String str, FontRenderContext frc) {
  1776. char[] array = str.toCharArray();
  1777. return getStringBounds(array, 0, array.length, frc);
  1778. }
  1779. /**
  1780. * Returns the logical bounds of the specified <code>String</code> in
  1781. * the specified <code>FontRenderContext</code>. The logical bounds
  1782. * contains the origin, ascent, advance, and height, which includes
  1783. * the leading. The logical bounds does not always enclose all the
  1784. * text. For example, in some languages and in some fonts, accent
  1785. * marks can be positioned above the ascent or below the descent.
  1786. * To obtain a visual bounding box, which encloses all the text,
  1787. * use the {@link TextLayout#getBounds() getBounds} method of
  1788. * <code>TextLayout</code>.
  1789. * @param str the specified <code>String</code>
  1790. * @param beginIndex the initial offset of <code>str</code>
  1791. * @param limit the end offset of <code>str</code>
  1792. * @param frc the specified <code>FontRenderContext</code>
  1793. * @return a <code>Rectangle2D</code> that is the bounding box of the
  1794. * specified <code>String</code> in the specified
  1795. * <code>FontRenderContext</code>.
  1796. * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
  1797. * less than zero, or <code>limit</code> is greater than the
  1798. * length of <code>str</code>, or <code>beginIndex</code>
  1799. * is greater than <code>limit</code>.
  1800. * @see FontRenderContext
  1801. * @see Font#createGlyphVector
  1802. * @since 1.2
  1803. */
  1804. public Rectangle2D getStringBounds( String str,
  1805. int beginIndex, int limit,
  1806. FontRenderContext frc) {
  1807. String substr = str.substring(beginIndex, limit);
  1808. return getStringBounds(substr, frc);
  1809. }
  1810. /**
  1811. * Returns the logical bounds of the specified array of characters
  1812. * in the specified <code>FontRenderContext</code>. The logical
  1813. * bounds contains the origin, ascent, advance, and height, which
  1814. * includes the leading. The logical bounds does not always enclose
  1815. * all the text. For example, in some languages and in some fonts,
  1816. * accent marks can be positioned above the ascent or below the
  1817. * descent. To obtain a visual bounding box, which encloses all the
  1818. * text, use the {@link TextLayout#getBounds() getBounds} method of
  1819. * <code>TextLayout</code>.
  1820. * @param chars an array of characters
  1821. * @param beginIndex the initial offset in the array of
  1822. * characters
  1823. * @param limit the end offset in the array of characters
  1824. * @param frc the specified <code>FontRenderContext</code>
  1825. * @return a <code>Rectangle2D</code> that is the bounding box of the
  1826. * specified array of characters in the specified
  1827. * <code>FontRenderContext</code>.
  1828. * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
  1829. * less than zero, or <code>limit</code> is greater than the
  1830. * length of <code>chars</code>, or <code>beginIndex</code>
  1831. * is greater than <code>limit</code>.
  1832. * @see FontRenderContext
  1833. * @see Font#createGlyphVector
  1834. * @since 1.2
  1835. */
  1836. public Rectangle2D getStringBounds(char [] chars,
  1837. int beginIndex, int limit,
  1838. FontRenderContext frc) {
  1839. if (beginIndex < 0) {
  1840. throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
  1841. }
  1842. if (limit > chars.length) {
  1843. throw new IndexOutOfBoundsException("limit: " + limit);
  1844. }
  1845. if (beginIndex > limit) {
  1846. throw new IndexOutOfBoundsException("range length: " + (limit - beginIndex));
  1847. }
  1848. // this code should be in textlayout
  1849. // quick check for simple text, assume GV ok to use if simple
  1850. boolean simple = true;
  1851. for (int i = beginIndex; i < limit; ++i) {
  1852. char c = chars[i];
  1853. if (c >= '\u0590' && c <= '\u206f') {
  1854. simple = false;
  1855. break;
  1856. }
  1857. }
  1858. if (simple) {
  1859. GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex, limit - beginIndex, frc);
  1860. return gv.getLogicalBounds();
  1861. } else {
  1862. // need char array constructor on textlayout
  1863. String str = new String(chars, beginIndex, limit - beginIndex);
  1864. TextLayout tl = new TextLayout(str, this, frc);
  1865. return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(), tl.getDescent() + tl.getLeading());
  1866. }
  1867. }
  1868. /**
  1869. * Returns the logical bounds of the characters indexed in the
  1870. * specified {@link CharacterIterator} in the
  1871. * specified <code>FontRenderContext</code>. The logical bounds
  1872. * contains the origin, ascent, advance, and height, which includes
  1873. * the leading. The logical bounds does not always enclose all the
  1874. * text. For example, in some languages and in some fonts, accent
  1875. * marks can be positioned above the ascent or below the descent.
  1876. * To obtain a visual bounding box, which encloses all the text,
  1877. * use the {@link TextLayout#getBounds() getBounds} method of
  1878. * <code>TextLayout</code>.
  1879. * @param ci the specified <code>CharacterIterator</code>
  1880. * @param beginIndex the initial offset in <code>ci</code>
  1881. * @param limit the end offset in <code>ci</code>
  1882. * @param frc the specified <code>FontRenderContext</code>
  1883. * @return a <code>Rectangle2D</code> that is the bounding box of the
  1884. * characters indexed in the specified <code>CharacterIterator</code>
  1885. * in the specified <code>FontRenderContext</code>.
  1886. * @see FontRenderContext
  1887. * @see Font#createGlyphVector
  1888. * @since 1.2
  1889. * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
  1890. * less than the start index of <code>ci</code>, or
  1891. * <code>limit</code> is greater than the end index of
  1892. * <code>ci</code>, or <code>beginIndex</code> is greater
  1893. * than <code>limit</code>
  1894. */
  1895. public Rectangle2D getStringBounds(CharacterIterator ci,
  1896. int beginIndex, int limit,
  1897. FontRenderContext frc) {
  1898. int start = ci.getBeginIndex();
  1899. int end = ci.getEndIndex();
  1900. if (beginIndex < start) {
  1901. throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
  1902. }
  1903. if (limit > end) {
  1904. throw new IndexOutOfBoundsException("limit: " + limit);
  1905. }
  1906. if (beginIndex > limit) {
  1907. throw new IndexOutOfBoundsException("range length: " + (limit - beginIndex));
  1908. }
  1909. char[] arr = new char[limit - beginIndex];
  1910. ci.setIndex(beginIndex);
  1911. for(int idx = 0; idx < arr.length; idx++) {
  1912. arr[idx] = ci.current();
  1913. ci.next();
  1914. }
  1915. return getStringBounds(arr,0,arr.length,frc);
  1916. }
  1917. /**
  1918. * Returns the bounds for the character with the maximum
  1919. * bounds as defined in the specified <code>FontRenderContext</code>.
  1920. * @param frc the specified <code>FontRenderContext</code>
  1921. * @return a <code>Rectangle2D</code> that is the bounding box
  1922. * for the character with the maximum bounds.
  1923. */
  1924. public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
  1925. float [] metrics = new float[4];
  1926. getFont2D().getFontMetrics(this, frc, metrics);
  1927. return new Rectangle2D.Float(0, -metrics[0],
  1928. metrics[3],
  1929. metrics[0] + metrics[1] + metrics[2]);
  1930. }
  1931. /**
  1932. * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
  1933. * mapping characters to glyphs one-to-one based on the
  1934. * Unicode cmap in this <code>Font</code>. This method does no other
  1935. * processing besides the mapping of glyphs to characters. This
  1936. * means that this method is not useful for some scripts, such
  1937. * as Arabic, Hebrew, Thai, and Indic, that require reordering,
  1938. * shaping, or ligature substitution.
  1939. * @param frc the specified <code>FontRenderContext</code>
  1940. * @param str the specified <code>String</code>
  1941. * @return a new <code>GlyphVector</code> created with the
  1942. * specified <code>String</code> and the specified
  1943. * <code>FontRenderContext</code>.
  1944. */
  1945. public GlyphVector createGlyphVector(FontRenderContext frc, String str)
  1946. {
  1947. return (GlyphVector)new StandardGlyphVector(this, str, frc);
  1948. }
  1949. /**
  1950. * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
  1951. * mapping characters to glyphs one-to-one based on the
  1952. * Unicode cmap in this <code>Font</code>. This method does no other
  1953. * processing besides the mapping of glyphs to characters. This
  1954. * means that this method is not useful for some scripts, such
  1955. * as Arabic, Hebrew, Thai, and Indic, that require reordering,
  1956. * shaping, or ligature substitution.
  1957. * @param frc the specified <code>FontRenderContext</code>
  1958. * @param chars the specified array of characters
  1959. * @return a new <code>GlyphVector</code> created with the
  1960. * specified array of characters and the specified
  1961. * <code>FontRenderContext</code>.
  1962. */
  1963. public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars)
  1964. {
  1965. return (GlyphVector)new StandardGlyphVector(this, chars, frc);
  1966. }
  1967. /**
  1968. * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
  1969. * mapping the specified characters to glyphs one-to-one based on the
  1970. * Unicode cmap in this <code>Font</code>. This method does no other
  1971. * processing besides the mapping of glyphs to characters. This
  1972. * means that this method is not useful for some scripts, such
  1973. * as Arabic, Hebrew, Thai, and Indic, that require reordering,
  1974. * shaping, or ligature substitution.
  1975. * @param frc the specified <code>FontRenderContext</code>
  1976. * @param ci the specified <code>CharacterIterator</code>
  1977. * @return a new <code>GlyphVector</code> created with the
  1978. * specified <code>CharacterIterator</code> and the specified
  1979. * <code>FontRenderContext</code>.
  1980. */
  1981. public GlyphVector createGlyphVector( FontRenderContext frc,
  1982. CharacterIterator ci)
  1983. {
  1984. return (GlyphVector)new StandardGlyphVector(this, ci, frc);
  1985. }
  1986. /**
  1987. * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
  1988. * mapping characters to glyphs one-to-one based on the
  1989. * Unicode cmap in this <code>Font</code>. This method does no other
  1990. * processing besides the mapping of glyphs to characters. This
  1991. * means that this method is not useful for some scripts, such
  1992. * as Arabic, Hebrew, Thai, and Indic, that require reordering,
  1993. * shaping, or ligature substitution.
  1994. * @param frc the specified <code>FontRenderContext</code>
  1995. * @param glyphCodes the specified integer array
  1996. * @return a new <code>GlyphVector</code> created with the
  1997. * specified integer array and the specified
  1998. * <code>FontRenderContext</code>.
  1999. */
  2000. public GlyphVector createGlyphVector( FontRenderContext frc,
  2001. int [] glyphCodes)
  2002. {
  2003. return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc);
  2004. }
  2005. /**
  2006. * Returns a new <code>GlyphVector</code> object, performing full
  2007. * layout of the text if possible. Full layout is required for
  2008. * complex text, such as Arabic or Hindi. Support for different
  2009. * scripts depends on the font and implementation.
  2010. * <p
  2011. * Layout requires bidi analysis, as performed by
  2012. * <code>Bidi</code>, and should only be performed on text that
  2013. * has a uniform direction. The direction is indicated in the
  2014. * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a
  2015. * right-to-left (Arabic and Hebrew) run direction, or
  2016. * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English)
  2017. * run direction.
  2018. * <p>
  2019. * In addition, some operations, such as Arabic shaping, require
  2020. * context, so that the characters at the start and limit can have
  2021. * the proper shapes. Sometimes the data in the buffer outside
  2022. * the provided range does not have valid data. The values
  2023. * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be
  2024. * added to the flags parameter to indicate that the text before
  2025. * start, or after limit, respectively, should not be examined
  2026. * for context.
  2027. * <p>
  2028. * All other values for the flags parameter are reserved.
  2029. *
  2030. * @param frc the specified <code>FontRenderContext</code>
  2031. * @param text the text to layout
  2032. * @param start the start of the text to use for the <code>GlyphVector</code>
  2033. * @param limit the limit of the text to use for the <code>GlyphVector</code>
  2034. * @param flags control flags as described above
  2035. * @return a new <code>GlyphVector</code> representing the text between
  2036. * start and limit, with glyphs chosen and positioned so as to best represent
  2037. * the text
  2038. * @throws ArrayIndexOutOfBoundsException if start or limit is
  2039. * out of bounds
  2040. * @see java.text.Bidi
  2041. * @see #LAYOUT_LEFT_TO_RIGHT
  2042. * @see #LAYOUT_RIGHT_TO_LEFT
  2043. * @see #LAYOUT_NO_START_CONTEXT
  2044. * @see #LAYOUT_NO_LIMIT_CONTEXT
  2045. */
  2046. public GlyphVector layoutGlyphVector(FontRenderContext frc,
  2047. char[] text,
  2048. int start,
  2049. int limit,
  2050. int flags) {
  2051. GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines
  2052. StandardGlyphVector gv = gl.layout(this, frc, text,
  2053. start, limit, flags, null);
  2054. GlyphLayout.done(gl);
  2055. return gv;
  2056. }
  2057. /**
  2058. * A flag to layoutGlyphVector indicating that text is left-to-right as
  2059. * determined by Bidi analysis.
  2060. */
  2061. public static final int LAYOUT_LEFT_TO_RIGHT = 0;
  2062. /**
  2063. * A flag to layoutGlyphVector indicating that text is right-to-left as
  2064. * determined by Bidi analysis.
  2065. */
  2066. public static final int LAYOUT_RIGHT_TO_LEFT = 1;
  2067. /**
  2068. * A flag to layoutGlyphVector indicating that text in the char array
  2069. * before the indicated start should not be examined.
  2070. */
  2071. public static final int LAYOUT_NO_START_CONTEXT = 2;
  2072. /**
  2073. * A flag to layoutGlyphVector indicating that text in the char array
  2074. * after the indicated limit should not be examined.
  2075. */
  2076. public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
  2077. private static void applyTransform(AffineTransform trans, Map attributes) {
  2078. if (trans == null) {
  2079. throw new IllegalArgumentException("transform must not be null");
  2080. }
  2081. if (trans.isIdentity()) {
  2082. attributes.remove(TextAttribute.TRANSFORM);
  2083. } else {
  2084. attributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans));
  2085. }
  2086. }
  2087. private static void applyStyle(int style, Map attributes) {
  2088. if ((style & BOLD) != 0) {
  2089. attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
  2090. } else {
  2091. attributes.remove(TextAttribute.WEIGHT);
  2092. }
  2093. if ((style & ITALIC) != 0) {
  2094. attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
  2095. } else {
  2096. attributes.remove(TextAttribute.POSTURE);
  2097. }
  2098. }
  2099. private static void applySize(float size, Map attributes) {
  2100. attributes.put(TextAttribute.SIZE, new Float(size));
  2101. }
  2102. /*
  2103. * Initialize JNI field and method IDs
  2104. */
  2105. private static native void initIDs();
  2106. private native void pDispose();
  2107. /**
  2108. * Disposes the native <code>Font</code> object.
  2109. */
  2110. protected void finalize() throws Throwable {
  2111. if (this.peer != null) {
  2112. pDispose();
  2113. }
  2114. super.finalize();
  2115. }
  2116. }