1. /*
  2. * @(#)Font.java 1.131 01/11/29
  3. *
  4. * Copyright 2002 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.TextAttribute;
  9. import java.awt.geom.AffineTransform;
  10. import java.awt.geom.Point2D;
  11. import java.awt.geom.Rectangle2D;
  12. import java.awt.peer.FontPeer;
  13. import java.text.AttributedCharacterIterator.Attribute;
  14. import java.text.CharacterIterator;
  15. import java.text.StringCharacterIterator;
  16. import java.util.Locale;
  17. import java.util.ResourceBundle;
  18. import java.util.MissingResourceException;
  19. import java.util.Hashtable;
  20. import sun.awt.font.FontNameAliases;
  21. import java.util.Map;
  22. import sun.awt.font.NativeFontWrapper;
  23. import sun.awt.font.StandardGlyphVector;
  24. import java.awt.font.FontRenderContext;
  25. import java.awt.font.LineMetrics;
  26. import java.awt.font.GlyphVector;
  27. import java.awt.font.TextLayout;
  28. import java.awt.font.TransformAttribute;
  29. import sun.java2d.SunGraphicsEnvironment;
  30. import sun.java2d.loops.RasterOutputManager;
  31. import java.lang.StringIndexOutOfBoundsException;
  32. import java.lang.ArrayIndexOutOfBoundsException;
  33. /**
  34. * The <code>Font</code> class represents fonts. The capabilities of this
  35. * class have been extended over the java.awt.Font class in JDK(tm) 1.1
  36. * and earlier releases to provide for developers the ability to utilize
  37. * more sophisticated typographic features.
  38. * <p>
  39. * It is important to present the concepts behind using the words
  40. * character and glyph separately. A <b>character</b> is a symbol that
  41. * represents items like letters and numbers in a particular writing
  42. * system. For example, <i>lowercase-g</i> is a character. When a
  43. * particular character has been rendered, a shape
  44. * now represents this character. This shape is called a <b>glyph</b>.
  45. * <p>
  46. * Chararcter encoding is a conversion table that maps character codes
  47. * to glyph codes in the font. The character encoding used in the
  48. * Java(tm) 2D API is Unicode. For more information on Unicode you can
  49. * visit the site
  50. * <a href="http://www.unicode.org">http://www.unicode.org</a>.
  51. * <p>
  52. * Characters and glyphs do not have one-to-one correspondence. For
  53. * example, <i>lowercase-a acute</i> can be represented by two glyphs:
  54. * <i>lowercase-a</i> and <i>acute</i>.
  55. * Another example is ligatures such as <i>ligature -fi</i> which is a
  56. * single glyph representing two characters, <i>f</i> and <i>i</i>.
  57. * <p>
  58. * A <code>Font</code> is a collection of glyphs. A <code>Font</code>
  59. * can have many faces, such as heavy, medium, oblique, gothic and
  60. * regular. All of these faces have similar typographic design.
  61. * <p>
  62. * There are three different names that you can get from a
  63. * <code>Font</code> object. The <i>logical font name</i> is the same as
  64. * that used by java.awt.Font in JDK 1.1 and earlier releases.
  65. * The <i>font face name</i>, or just <i>font name</i> for
  66. * short, is the name of a particular font face, like Helvetica Bold. The
  67. * <i>family name</i> is the name of the font family that determines the
  68. * typographic design across several faces, like Helvetica. The font face
  69. * name is the one that should be used to specify fonts. This name
  70. * signifies actual fonts in the host system, and does not identify font
  71. * names with the shape of font characters as the logical font name does.
  72. * <p>
  73. * The <code>Font</code> class represents an instance of a font face from
  74. * a collection of font faces that are present in the system resources
  75. * of the host system. As examples, Arial Bold and Courier Bold Italic
  76. * are font faces. There can be several <code>Font</code> objects
  77. * associated with a font face, each differing in size, style, transform
  78. * and font features.
  79. * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method
  80. * of the <code>GraphicsEnvironment</code> class returns an
  81. * array of all font faces available in the system. These font faces are
  82. * returned as <code>Font</code> objects with a size of 1, identity
  83. * transform and default font features. These
  84. * base fonts can then be used to derive new <code>Font</code> objects
  85. * with varying sizes, styles, transforms and font features via the
  86. * <code>deriveFont</code> methods in this class.
  87. * @see GraphicsEnvironment#getAllFonts
  88. * @version 10 Feb 1997
  89. */
  90. public class Font implements java.io.Serializable
  91. {
  92. static {
  93. /* ensure that the necessary native libraries are loaded */
  94. Toolkit.loadLibraries();
  95. initIDs();
  96. }
  97. /**
  98. * A map of font attributes available in this font.
  99. * Attributes include things like ligatures and glyph substitution.
  100. * @return the attributes map
  101. *
  102. * @serial
  103. * @see getAttributes()
  104. */
  105. private Hashtable fRequestedAttributes;
  106. private static final Map EMPTY_MAP = new Hashtable(5, (float)0.9);
  107. /*
  108. * Constants to be used for styles. Can be combined to mix
  109. * styles.
  110. */
  111. /**
  112. * The plain style constant.
  113. */
  114. public static final int PLAIN = 0;
  115. /**
  116. * The bold style constant. This can be combined with the other style
  117. * constants (except PLAIN) for mixed styles.
  118. */
  119. public static final int BOLD = 1;
  120. /**
  121. * The italicized style constant. This can be combined with the other
  122. * style constants (except PLAIN) for mixed styles.
  123. */
  124. public static final int ITALIC = 2;
  125. /**
  126. * The baseline used in most Roman scripts when laying out text
  127. */
  128. public static final int ROMAN_BASELINE = 0;
  129. /**
  130. * The baseline used in ideographic scripts like Chinese, Japanese,
  131. * and Korean when laying out text
  132. */
  133. public static final int CENTER_BASELINE = 1;
  134. /**
  135. * The baseline used in Devanigiri and similar scripts when laying
  136. * out text
  137. */
  138. public static final int HANGING_BASELINE = 2;
  139. /**
  140. * The logical name of this <code>Font</code>, as passed to the
  141. * constructor.
  142. * @since JDK1.0
  143. *
  144. * @serial
  145. * @see #getName
  146. */
  147. protected String name;
  148. /**
  149. * The style of this <code>Font</code>, as passed to the constructor.
  150. * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
  151. * @since JDK1.0
  152. *
  153. * @serial
  154. * @see #getStyle()
  155. */
  156. protected int style;
  157. /**
  158. * The point size of this <code>Font</code>, rounded to integer.
  159. * @since JDK1.0
  160. *
  161. * @serial
  162. * @see #getSize()
  163. */
  164. protected int size;
  165. /**
  166. * The point size of this <code>Font</code> in <code>float</code>.
  167. *
  168. * @serial
  169. * @see #getSize()
  170. * @see #getSize2D()
  171. */
  172. protected float pointSize;
  173. /**
  174. * The platform specific font information.
  175. */
  176. private transient FontPeer peer;
  177. private transient long pData; // native JDK1.1 font pointer
  178. private transient long pNativeFont; // native JDK1.2 font reference
  179. // cached values - performance
  180. private transient int numGlyphs = -1;
  181. private transient int missingGlyph = -1;
  182. private transient int canRotate = -1;
  183. private transient double[] matrix;
  184. private static Hashtable fontCache = new Hashtable(5, (float)0.9);
  185. /*
  186. * JDK 1.1 serialVersionUID
  187. */
  188. private static final long serialVersionUID = -4206021311591459213L;
  189. /**
  190. * Gets the peer of this <code>Font</code>.
  191. * @return the peer of the <code>Font</code>.
  192. * @since JDK1.1
  193. * @deprecated Font rendering is now platform independent.
  194. */
  195. public FontPeer getPeer(){
  196. return getPeer_NoClientCode();
  197. }
  198. // NOTE: This method is called by privileged threads.
  199. // We implement this functionality in a package-private method
  200. // to insure that it cannot be overridden by client subclasses.
  201. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  202. final FontPeer getPeer_NoClientCode() {
  203. if(peer == null) {
  204. if (true || RasterOutputManager.usesPlatformFont()) {
  205. Toolkit tk = Toolkit.getDefaultToolkit();
  206. this.peer = tk.getFontPeer(name, style);
  207. }
  208. }
  209. return peer;
  210. }
  211. private void initializeFont(Hashtable attributes) {
  212. if (this.name == null) {
  213. this.name = "Default";
  214. }
  215. if (attributes == null) {
  216. fRequestedAttributes = new Hashtable(5, (float)0.9);
  217. fRequestedAttributes.put(TextAttribute.TRANSFORM,
  218. new TransformAttribute(new AffineTransform()));
  219. fRequestedAttributes.put(TextAttribute.FAMILY, name);
  220. fRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
  221. if ((style & BOLD) != 0) {
  222. fRequestedAttributes.put(
  223. TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
  224. }
  225. if ((style & ITALIC) != 0) {
  226. fRequestedAttributes.put(
  227. TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
  228. }
  229. } else {
  230. fRequestedAttributes = ffApply(style, attributes);
  231. }
  232. SunGraphicsEnvironment env =
  233. (SunGraphicsEnvironment)GraphicsEnvironment
  234. .getLocalGraphicsEnvironment();
  235. String localName = env.mapFamilyName(this.name, this.style);
  236. NativeFontWrapper.initializeFont(this, localName, style); // sets pNativeFont
  237. // System.out.println("Initializing font: '" + localName + "'.");
  238. }
  239. /**
  240. * Creates a new <code>Font</code> from the specified name, style and
  241. * point size.
  242. * @param name the font name. This can be a logical font name or a
  243. * font face name. A logical name must be either: Dialog, DialogInput,
  244. * Monospaced, Serif, SansSerif, or Symbol.
  245. * @param style the style constant for the <code>Font</code>
  246. * The style argument is an integer bitmask that may
  247. * be PLAIN, or a bitwise union of BOLD and/or ITALIC
  248. * (for example, ITALIC or BOLD|ITALIC). Any other
  249. * bits set in the style parameter are ignored.
  250. * If the style argument does not conform to one of the expected
  251. * integer bitmasks then the style is set to PLAIN.
  252. * @param size the point size of the <code>Font</code>
  253. * @see GraphicsEnvironment#getAllFonts
  254. * @see GraphicsEnvironment#getAvailableFontFamilyNames
  255. * @since JDK1.0
  256. */
  257. public Font(String name, int style, int size) {
  258. this.name = name;
  259. this.style = style;
  260. this.size = size;
  261. this.pointSize = size;
  262. initializeFont(null);
  263. }
  264. private Font(String name, int style, float sizePts) {
  265. this.name = name;
  266. this.style = style;
  267. this.size = (int)(sizePts + 0.5);
  268. this.pointSize = sizePts;
  269. initializeFont(null);
  270. }
  271. /**
  272. * Creates a new <code>Font</code> with the specified attributes.
  273. * This <code>Font</code> only recognizes keys defined in
  274. * {@link TextAttribute} as attributes. If <code>attributes</code>
  275. * is <code>null</code>, a new <code>Font</code> is initialized
  276. * with default attributes.
  277. * @param attributes the attributes to assign to the new
  278. * <code>Font</code>, or <code>null</code>
  279. */
  280. public Font(Map attributes){
  281. this.pointSize = 12;
  282. this.size = 12;
  283. if((attributes != null) &&
  284. (!attributes.equals(EMPTY_MAP)))
  285. {
  286. Object obj;
  287. fRequestedAttributes = new Hashtable(attributes);
  288. if ((obj = attributes.get(TextAttribute.FAMILY)) != null) {
  289. this.name = (String)obj;
  290. }
  291. if ((obj = attributes.get(TextAttribute.WEIGHT)) != null){
  292. if(obj.equals(TextAttribute.WEIGHT_BOLD)) {
  293. this.style |= BOLD;
  294. }
  295. }
  296. if ((obj = attributes.get(TextAttribute.POSTURE)) != null){
  297. if(obj.equals(TextAttribute.POSTURE_OBLIQUE)) {
  298. this.style |= ITALIC;
  299. }
  300. }
  301. if ((obj = attributes.get(TextAttribute.SIZE)) != null){
  302. this.pointSize = ((Float)obj).floatValue();
  303. this.size = (int)(this.pointSize + 0.5);
  304. }
  305. fontCache.put(attributes, this);
  306. }
  307. initializeFont(fRequestedAttributes);
  308. }
  309. /**
  310. * Returns a <code>Font</code> appropriate to this attribute set.
  311. * @param attributes the attributes to assign to the new
  312. * <code>Font</code>
  313. * @return a new <code>Font</code> created with the specified
  314. * attributes.
  315. * @since JDK1.2
  316. */
  317. public static Font getFont(Map attributes) {
  318. Font font = (Font)attributes.get(TextAttribute.FONT);
  319. if (font != null) {
  320. return font;
  321. }
  322. font = (Font)fontCache.get(attributes);
  323. if (font != null) {
  324. return font;
  325. }
  326. Hashtable copiedAttributes = new Hashtable(attributes);
  327. font = new Font(attributes);
  328. fontCache.put(copiedAttributes, font);
  329. return font;
  330. }
  331. /**
  332. * Returns a copy of the transform associated with this
  333. * <code>Font</code>.
  334. * @param an {@link AffineTransform} object representing the
  335. * transform attribute of this <code>Font</code> object.
  336. */
  337. public AffineTransform getTransform() {
  338. Object obj = fRequestedAttributes.get(TextAttribute.TRANSFORM);
  339. if (obj != null) {
  340. if( obj instanceof TransformAttribute ){
  341. return ((TransformAttribute)obj).getTransform();
  342. }
  343. else {
  344. if ( obj instanceof AffineTransform){
  345. return new AffineTransform((AffineTransform)obj);
  346. }
  347. }
  348. }else{
  349. obj = new AffineTransform();
  350. }
  351. return (AffineTransform)obj;
  352. }
  353. /**
  354. * Returns the family name of this <code>Font</code>. For example,
  355. * Helvetica could be returned as a family name for the font
  356. * face name of Helvetica Bold.
  357. * Use <code>getName</code> to get the logical name of the font.
  358. * Use <code>getFontName</code> to get the font face name of the font.
  359. * @return a <code>String</code> that is the family name of this
  360. * <code>Font</code>.
  361. * @see #getName
  362. * @see #getFontName
  363. * @since JDK1.2
  364. */
  365. public String getFamily() {
  366. return getFamily_NoClientCode();
  367. }
  368. // NOTE: This method is called by privileged threads.
  369. // We implement this functionality in a package-private
  370. // method to insure that it cannot be overridden by client
  371. // subclasses.
  372. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  373. final String getFamily_NoClientCode() {
  374. return getFamily(Locale.getDefault());
  375. }
  376. /**
  377. * Returns the family name of this <code>Font</code>, localized for
  378. * the specified locale. For example, Helvetica could be returned as a
  379. * family name for the font face name of Helvetica Bold.
  380. * Use <code>getFontName</code> to get the font face name of the font.
  381. * @param l locale for which to get the family name
  382. * @return a <code>String</code> representing the family name of the
  383. * font, localized for the specified locale.
  384. * @see #getFontName
  385. * @see java.util.Locale
  386. * @since JDK1.2
  387. */
  388. public String getFamily(Locale l) {
  389. short lcid = getLcidFromLocale(l);
  390. return NativeFontWrapper.getFamilyName(this, lcid);
  391. }
  392. /**
  393. * Returns the postscript name of this <code>Font</code>.
  394. * Use <code>getFamily</code> to get the family name of the font.
  395. * Use <code>getFontName</code> to get the font face name of the font.
  396. * @return a <code>String</code> representing the postscript name of
  397. * this <code>Font</code>.
  398. * @since JDK1.2
  399. */
  400. public String getPSName() {
  401. return getFontName();
  402. }
  403. /**
  404. * Returns the logical name of this <code>Font</code>.
  405. * Use <code>getFamily</code> to get the family name of the font.
  406. * Use <code>getFontName</code> to get the font face name of the font.
  407. * @return a <code>String</code> representing the logical name of
  408. * this <code>Font</code>.
  409. * @see #getFamily
  410. * @see #getFontName
  411. * @since JDK1.0
  412. */
  413. public String getName() {
  414. return new String(name);
  415. }
  416. /**
  417. * Returns the font face name of this <code>Font</code>. For example,
  418. * Helvetica Bold could be returned as a font face name.
  419. * Use <code>getFamily</code> to get the family name of the font.
  420. * Use <code>getName</code> to get the logical name of the font.
  421. * @return a <code>String</code> representing the font face name of
  422. * this <code>Font</code>.
  423. * @see #getFamily
  424. * @see #getName
  425. * @since JDK1.2
  426. */
  427. public String getFontName() {
  428. return getFontName(Locale.getDefault());
  429. }
  430. /**
  431. * Returns the font face name of the <code>Font</code>, localized
  432. * for the specified locale. For example, Helvetica Fett could be
  433. * returned as the font face name.
  434. * Use <code>getFamily</code> to get the family name of the font.
  435. * @param l a locale for which to get the font face name
  436. * @return a <code>String</code> representing the font face name,
  437. * localized for the specified locale.
  438. * @see #getFamily
  439. * @see java.util.Locale
  440. */
  441. public String getFontName(Locale l) {
  442. short lcid = getLcidFromLocale(l);
  443. return NativeFontWrapper.getFullName(this, lcid);
  444. }
  445. /**
  446. * Returns the style of this <code>Font</code>. The style can be
  447. * PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
  448. * @return the style of this <code>Font</code>
  449. * @see #isPlain
  450. * @see #isBold
  451. * @see #isItalic
  452. * @since JDK1.0
  453. */
  454. public int getStyle() {
  455. return style;
  456. }
  457. /**
  458. * Returns the point size of this <code>Font</code>, rounded to
  459. * an integer.
  460. * Most users are familiar with the idea of using <i>point size</i> to
  461. * specify the size of glyphs in a font. This point size defines a
  462. * measurement between the baseline of one line to the baseline of the
  463. * following line in a single spaced text document. The point size is
  464. * based on <i>typographic points</i>, approximately 1/72 of an inch.
  465. * <p>
  466. * The Java(tm)2D API adopts the convention that one point is
  467. * equivalent to one unit in user coordinates. When using a
  468. * normalized transform for converting user space coordinates to
  469. * device space coordinates 72 user
  470. * space units equal 1 inch in device space. In this case one point
  471. * is 1/72 of an inch.
  472. * @return the point size of this <code>Font</code> in 1/72 of an
  473. * inch units.
  474. * @see #getSize2D
  475. * @see GraphicsConfiguration#getDefaultTransform
  476. * @see GraphicsConfiguration#getNormalizingTransform
  477. * @since JDK1.0
  478. */
  479. public int getSize() {
  480. return size;
  481. }
  482. /**
  483. * Returns the point size of this <code>Font</code> in
  484. * <code>float</code> value.
  485. * @return the point size of this <code>Font</code> as a
  486. * <code>float</code> value.
  487. * @see #getSize
  488. * @since JDK1.2
  489. */
  490. public float getSize2D() {
  491. return pointSize;
  492. }
  493. /**
  494. * Indicates whether or not this <code>Font</code> object's style is
  495. * PLAIN.
  496. * @return <code>true</code> if this <code>Font</code> has a
  497. * PLAIN sytle;
  498. * <code>false</code> otherwise.
  499. * @see java.awt.Font#getStyle
  500. * @since JDK1.0
  501. */
  502. public boolean isPlain() {
  503. return style == 0;
  504. }
  505. /**
  506. * Indicates whether or not this <code>Font</code> object's style is
  507. * BOLD.
  508. * @return <code>true</code> if this <code>Font</code> object's
  509. * style is BOLD;
  510. * <code>false</code> otherwise.
  511. * @see java.awt.Font#getStyle
  512. * @since JDK1.0
  513. */
  514. public boolean isBold() {
  515. return (style & BOLD) != 0;
  516. }
  517. /**
  518. * Indicates whether or not this <code>Font</code> object's style is
  519. * ITALIC.
  520. * @return <code>true</code> if this <code>Font</code> object's
  521. * style is ITALIC;
  522. * <code>false</code> otherwise.
  523. * @see java.awt.Font#getStyle
  524. * @since JDK1.0
  525. */
  526. public boolean isItalic() {
  527. return (style & ITALIC) != 0;
  528. }
  529. /**
  530. * Returns a <code>Font</code> object from the system properties list.
  531. * @param nm the property name
  532. * @return a <code>Font</code> object that the property name
  533. * describes.
  534. * @since JDK1.2
  535. */
  536. public static Font getFont(String nm) {
  537. return getFont(nm, null);
  538. }
  539. /**
  540. * Returns the <code>Font</code> that the <code>str</code>
  541. * argument describes. If <code>str</code> is <code>null</code>,
  542. * a new <code>Font</code> is returned with the name "dialog", a
  543. * size of 12 and a PLAIN style.
  544. * @param str the name of the font, or <code>null</code>
  545. * @return the <code>Font</code> object that <code>str</code>
  546. * describes, or a new default <code>Font</code> if
  547. * <code>str</code> is <code>null</code>.
  548. * @since JDK1.1
  549. */
  550. public static Font decode(String str) {
  551. String fontName = str;
  552. String fontSizeStr;
  553. int index;
  554. int fontSize = 12;
  555. int fontStyle = Font.PLAIN;
  556. if (str == null) {
  557. return new Font("dialog", fontStyle, fontSize);
  558. }
  559. int i = str.indexOf('-');
  560. if (i >= 0) {
  561. fontName = str.substring(0, i);
  562. str = str.substring(i+1);
  563. str = str.toLowerCase(); // name may be in upper/lower causing incorrect style matching
  564. index = str.indexOf ( "bold-italic" );
  565. if ( index != -1 ) {
  566. fontStyle = Font.BOLD | Font.ITALIC;
  567. }
  568. if ( index == -1 ) {
  569. index = str.indexOf ( "bolditalic" );
  570. if (index != -1) {
  571. fontStyle = Font.BOLD | Font.ITALIC;
  572. }
  573. }
  574. if ( index == -1 ) {
  575. index = str.indexOf ( "bold" );
  576. if ( index != -1 ) {
  577. fontStyle = Font.BOLD;
  578. }
  579. }
  580. if ( index == -1 ) {
  581. index = str.indexOf ( "italic" );
  582. if (index != -1) {
  583. fontStyle = Font.ITALIC;
  584. }
  585. }
  586. index = str.lastIndexOf ( "-" );
  587. if ( index != -1 ) {
  588. str = str.substring(index+1);
  589. }
  590. try {
  591. fontSize = Integer.valueOf(str).intValue();
  592. } catch (NumberFormatException e) {
  593. }
  594. } else if ( i == -1 ) {
  595. fontStyle = Font.PLAIN;
  596. fontSize = 12;
  597. str = str.toLowerCase();
  598. index = str.indexOf ( "bolditalic" );
  599. if (index != -1 ) {
  600. fontStyle = Font.BOLD | Font.ITALIC;
  601. }
  602. if ( index == -1 ) {
  603. index = str.indexOf ( "bold italic" );
  604. if ( index != -1 ) {
  605. fontStyle = Font.BOLD | Font.ITALIC;
  606. }
  607. }
  608. if ( index == -1 ) {
  609. index = str.indexOf ("bold");
  610. if ( index != -1 ) {
  611. fontStyle = Font.BOLD;
  612. }
  613. }
  614. if ( index == -1 ) {
  615. index = str.indexOf ("italic");
  616. if ( index != -1 )
  617. fontStyle = Font.ITALIC;
  618. }
  619. if ( index != -1 ) { // found a style
  620. fontName = fontName.substring(0, index );
  621. fontName = fontName.trim();
  622. }
  623. index = str.lastIndexOf (" " );
  624. if ( index != -1 ) {
  625. fontSizeStr = str.substring ( index );
  626. fontSizeStr = fontSizeStr.trim();
  627. try {
  628. fontSize = Integer.valueOf(fontSizeStr).intValue();
  629. } catch (NumberFormatException e) {
  630. }
  631. }
  632. }
  633. return new Font(fontName, fontStyle, fontSize);
  634. }
  635. /**
  636. * Gets the specified <code>Font</code> from the system properties
  637. * list. As in the <code>getProperty</code> method of
  638. * <code>System</code>, the first
  639. * argument is treated as the name of a system property to be
  640. * obtained. The <code>String</code> value of this property is then
  641. * interpreted as a <code>Font</code> object.
  642. * <p>
  643. * The property value should be one of the following forms:
  644. * <ul>
  645. * <li><em>fontname-style-pointsize</em>
  646. * <li><em>fontname-pointsize</em>
  647. * <li><em>fontname-style</em>
  648. * <li><em>fontname</em>
  649. * </ul>
  650. * where <i>style</i> is one of the three strings
  651. * <code>"BOLD"</code>, <code>"BOLDITALIC"</code>, or
  652. * <code>"ITALIC"</code>, and point size is a decimal
  653. * representation of the point size.
  654. * <p>
  655. * The default style is <code>PLAIN</code>. The default point size
  656. * is 12.
  657. * <p>
  658. * If the specified property is not found, the <code>font</code>
  659. * argument is returned instead.
  660. * @param nm the property name
  661. * @param font a default <code>Font</code> to return if property
  662. * <code>nm</code> is not defined
  663. * @return the <code>Font</code> value of the property.
  664. */
  665. public static Font getFont(String nm, Font font) {
  666. String str = null;
  667. try {
  668. str =System.getProperty(nm);
  669. } catch(SecurityException e) {
  670. }
  671. if (str == null) {
  672. return font;
  673. }
  674. return decode ( str );
  675. }
  676. /**
  677. * Returns a hashcode for this <code>Font</code>.
  678. * @return a hashcode value for this <code>Font</code>.
  679. * @since JDK1.0
  680. */
  681. public int hashCode() {
  682. return name.hashCode() ^ style ^ size;
  683. }
  684. /**
  685. * Compares this <code>Font</code> object to the specified
  686. * <code>Object</code>.
  687. * @param obj the <code>Object</code> to compare.
  688. * @return <code>true</code> if the objects are the same;
  689. * <code>false</code> otherwise.
  690. * @since JDK1.0
  691. */
  692. public boolean equals(Object obj) {
  693. if (obj == this) {
  694. return true;
  695. }
  696. if (obj != null) {
  697. try {
  698. Font font = (Font)obj;
  699. double[] thismat = this.getMatrix();
  700. double[] thatmat = font.getMatrix();
  701. return (size == font.size)
  702. && (pointSize == font.pointSize)
  703. && (style == font.style)
  704. && name.equals(font.name)
  705. && thismat[0] == thatmat[0]
  706. && thismat[1] == thatmat[1]
  707. && thismat[2] == thatmat[2]
  708. && thismat[3] == thatmat[3];
  709. }
  710. catch (ClassCastException e) {
  711. }
  712. }
  713. return false;
  714. }
  715. /**
  716. * Converts this <code>Font</code> object to a <code>String</code>
  717. * representation.
  718. * @return a <code>String</code> representation of this
  719. * <code>Font</code> object.
  720. * @since JDK1.0
  721. */
  722. // NOTE: This method may be called by privileged threads.
  723. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  724. public String toString() {
  725. String strStyle;
  726. if (isBold()) {
  727. strStyle = isItalic() ? "bolditalic" : "bold";
  728. } else {
  729. strStyle = isItalic() ? "italic" : "plain";
  730. }
  731. return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" +
  732. strStyle + ",size=" + size + "]";
  733. } // toString()
  734. /* Serialization support. A readObject method is neccessary because
  735. * the constructor creates the fonts peer, and we can't serialize the
  736. * peer. Similarly the computed font "family" may be different
  737. * at readObject time than at writeObject time. An integer version is
  738. * written so that future versions of this class will be able to recognize
  739. * serialized output from this one.
  740. */
  741. /**
  742. * The font Serializable Data Form.
  743. *
  744. * @serial
  745. */
  746. private int fontSerializedDataVersion = 1;
  747. /**
  748. * Writes default serializable fields to stream. Writes
  749. * a list of serializable ItemListener(s) as optional data.
  750. * The non-serializable ItemListner(s) are detected and
  751. * no attempt is made to serialize them.
  752. *
  753. * @serialData Null terminated sequence of 0 or more pairs.
  754. * The pair consists of a String and Object.
  755. * The String indicates the type of object and
  756. * is one of the following :
  757. * itemListenerK indicating and ItemListener object.
  758. *
  759. * @see AWTEventMulticaster.save(ObjectOutputStream, String, EventListener)
  760. * @see java.awt.Component.itemListenerK
  761. */
  762. private void writeObject(java.io.ObjectOutputStream s)
  763. throws java.lang.ClassNotFoundException,
  764. java.io.IOException
  765. {
  766. s.defaultWriteObject();
  767. }
  768. /**
  769. * Read the ObjectInputStream and if it isnt null
  770. * add a listener to receive item events fired
  771. * by the Font.
  772. * Unrecognised keys or values will be Ignored.
  773. * @serial
  774. * @see removeActionListener()
  775. * @see addActionListener()
  776. */
  777. private void readObject(java.io.ObjectInputStream s)
  778. throws java.lang.ClassNotFoundException,
  779. java.io.IOException
  780. {
  781. s.defaultReadObject();
  782. if (pointSize == 0) {
  783. pointSize = (float)size;
  784. }
  785. initializeFont(fRequestedAttributes);
  786. }
  787. /**
  788. * Returns the number of glyphs in this <code>Font</code>. Glyph codes
  789. * for this <code>Font</code> range from 0 to
  790. * <code>getNumGlyphs()</code> - 1.
  791. * @return the number of glyphs in this <code>Font</code>.
  792. * @since JDK1.2
  793. */
  794. public int getNumGlyphs() {
  795. if (numGlyphs == -1) {
  796. numGlyphs = NativeFontWrapper.getNumGlyphs(this);
  797. }
  798. return numGlyphs;
  799. }
  800. /**
  801. * Returns the glyphCode which is used when this <code>Font</code>
  802. * does not have a glyph for a specified unicode.
  803. * @return the glyphCode of this <code>Font</code>.
  804. * @since JDK1.2
  805. */
  806. public int getMissingGlyphCode() {
  807. if (missingGlyph == -1) {
  808. missingGlyph = NativeFontWrapper.getMissingGlyphCode(this);
  809. }
  810. return missingGlyph;
  811. }
  812. /**
  813. * get the transform matrix for this font.
  814. */
  815. private double[] getMatrix() {
  816. if (matrix == null) {
  817. float ptSize = this.getSize2D();
  818. AffineTransform tx = getTransform();
  819. tx.scale(ptSize, ptSize);
  820. matrix = new double[] { tx.getScaleX(), tx.getShearY(),
  821. tx.getShearX(), tx.getScaleY() };
  822. }
  823. return matrix;
  824. }
  825. /**
  826. * Returns the baseline appropriate for displaying this character.
  827. * <p>
  828. * Large fonts can support different writing systems, and each system can
  829. * use a different baseline.
  830. * The character argument determines the writing system to use. Clients
  831. * should not assume all characters use the same baseline.
  832. *
  833. * @param c a character used to identify the writing system
  834. * @return the baseline appropriate for the specified character.
  835. * @see LineMetrics#getBaselineOffsets
  836. * @see #ROMAN_BASELINE
  837. * @see #CENTER_BASELINE
  838. * @see #HANGING_BASELINE
  839. * @since JDK1.2
  840. */
  841. public byte getBaselineFor(char c) {
  842. return NativeFontWrapper.getBaselineFor(this, c);
  843. }
  844. /**
  845. * Returns a map of font attributes available in this
  846. * <code>Font</code>. Attributes include things like ligatures and
  847. * glyph substitution.
  848. * @return the attributes map of this <code>Font</code>.
  849. */
  850. public Map getAttributes(){
  851. return (Map)fRequestedAttributes.clone();
  852. }
  853. /**
  854. * Returns the keys of all the attributes supported by this
  855. * <code>Font</code>. These attributes can be used to derive other
  856. * fonts.
  857. * @return an array containing the keys of all the attributes
  858. * supported by this <code>Font</code>.
  859. * @since JDK1.2
  860. */
  861. public Attribute[] getAvailableAttributes(){
  862. Attribute attributes[] = {
  863. TextAttribute.FAMILY,
  864. TextAttribute.WEIGHT,
  865. TextAttribute.POSTURE,
  866. TextAttribute.SIZE
  867. };
  868. return attributes;
  869. }
  870. /**
  871. * Creates a new <code>Font</code> object by replicating this
  872. * <code>Font</code> object and applying a new style and size.
  873. * @param style the style for the new <code>Font</code>
  874. * @param size the size for the new <code>Font</code>
  875. * @return a new <code>Font</code> object.
  876. * @since JDK1.2
  877. */
  878. public Font deriveFont(int style, float size){
  879. return new Font(ffApply(style,
  880. ffApply(size, fRequestedAttributes)));
  881. }
  882. /**
  883. * Creates a new <code>Font</code> object by replicating this
  884. * <code>Font</code> object and applying a new style and transform.
  885. * @param style the style for the new <code>Font</code>
  886. * @param trans the <code>AffineTransform</code> associated with the
  887. * new <code>Font</code>
  888. * @return a new <code>Font</code> object.
  889. * @since JDK1.2
  890. */
  891. public Font deriveFont(int style, AffineTransform trans){
  892. return new Font(ffApply(style,
  893. ffApply(trans, fRequestedAttributes)));
  894. }
  895. /**
  896. * Creates a new <code>Font</code> object by replicating the current
  897. * <code>Font</code> object and applying a new size to it.
  898. * @param size the size for the new <code>Font</code>.
  899. * @return a new <code>Font</code> object.
  900. * @since JDK1.2
  901. */
  902. public Font deriveFont(float size){
  903. return new Font( ffApply(size, fRequestedAttributes));
  904. }
  905. /**
  906. * Creates a new <code>Font</code> object by replicating the current
  907. * <code>Font</code> object and applying a new transform to it.
  908. * @param trans the <code>AffineTransform</code> associated with the
  909. * new <code>Font</code>
  910. * @return a new <code>Font</code> object.
  911. * @since JDK1.2
  912. */
  913. public Font deriveFont(AffineTransform trans){
  914. return new Font(ffApply(trans, fRequestedAttributes));
  915. }
  916. /**
  917. * Creates a new <code>Font</code> object by replicating the current
  918. * <code>Font</code> object and applying a new style to it.
  919. * @param style the style for the new <code>Font</code>
  920. * @return a new <code>Font</code> object.
  921. * @since JDK1.2
  922. */
  923. public Font deriveFont(int style){
  924. return new Font(ffApply(style, fRequestedAttributes));
  925. }
  926. /**
  927. * Creates a new <code>Font</code> object by replicating the current
  928. * <code>Font</code> object and applying a new set of font attributes
  929. * to it.
  930. * @param attributes a map of attributes enabled for the new
  931. * <code>Font</code>
  932. * @return a new <code>Font</code> object.
  933. * @since JDK1.2
  934. */
  935. public Font deriveFont(Map attributes) {
  936. Hashtable newAttrs = new Hashtable(getAttributes());
  937. Attribute validAttribs[] = getAvailableAttributes();
  938. Object obj;
  939. for(int i = 0; i < validAttribs.length; i++){
  940. if ((obj = attributes.get(validAttribs[i])) != null) {
  941. newAttrs.put(validAttribs[i],obj);
  942. }
  943. }
  944. return new Font(newAttrs);
  945. }
  946. /**
  947. * Checks if this <code>Font</code> has a glyph for the specified
  948. * character.
  949. * @param c a unicode character code
  950. * @return <code>true</code> if this <code>Font</code> can display the
  951. * character; <code>false</code> otherwise.
  952. * @since JDK1.2
  953. */
  954. public boolean canDisplay(char c){
  955. return NativeFontWrapper.canDisplay(this, c);
  956. }
  957. /**
  958. * Indicates whether or not this <code>Font</code> can display a
  959. * specified <code>String</code>. For strings with Unicode encoding,
  960. * it is important to know if a particular font can display the
  961. * string. This method returns an offset into the <code>String</code>
  962. * <code>str</code> which is the first character this
  963. * <code>Font</code> cannot display without using the missing glyph
  964. * code. If the <code>Font</code> can display all characters, -1 is
  965. * returned.
  966. * @param str a <code>String</code> object
  967. * @return an offset into <code>str</code> that points
  968. * to the first character in <code>str</code> that this
  969. * <code>Font</code> cannot display; or <code>-1</code> if
  970. * this <code>Font</code> can display all characters in
  971. * <code>str</code>.
  972. * @since JDK1.2
  973. */
  974. public int canDisplayUpTo(String str) {
  975. return canDisplayUpTo(new StringCharacterIterator(str), 0,
  976. str.length());
  977. }
  978. /**
  979. * Indicates whether or not this <code>Font</code> can display
  980. * the characters in the specified <code>text</code>
  981. * starting at <code>start</code> and ending at
  982. * <code>limit</code>. This method is a convenience overload.
  983. * @param text the specified array of characters
  984. * @param start the specified starting offset into the specified array
  985. * of characters
  986. * @param limit the specified ending offset into the specified
  987. * array of characters
  988. * @since JDK1.2
  989. */
  990. public int canDisplayUpTo(char[] text, int start, int limit) {
  991. while (start < limit && canDisplay(text[start])) {
  992. ++start;
  993. }
  994. return start;
  995. }
  996. /**
  997. * Indicates whether or not this <code>Font</code> can display
  998. * the specified <code>String</code>. For strings with Unicode
  999. * encoding, it is important to know if a particular font can display
  1000. * the string. This method returns an offset
  1001. * into the <code>String</code> <code>str</code> which is the first
  1002. * character this <code>Font</code> cannot display without using the
  1003. * missing glyph code . If this <code>Font</code> can display all
  1004. * characters, <code>-1</code> is returned.
  1005. * @param text a {@link CharacterIterator} object
  1006. * @param start the specified starting offset into the specified array
  1007. * of characters
  1008. * @param limit the specified ending offset into the specified
  1009. * array of characters
  1010. * @return an offset into the <code>String</code> object that can be
  1011. * displayed by this <code>Font</code>.
  1012. * @since JDK1.2
  1013. */
  1014. public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
  1015. for (char c = iter.setIndex(start);
  1016. iter.getIndex() < limit && canDisplay(c);
  1017. c = iter.next()) {
  1018. }
  1019. return iter.getIndex();
  1020. }
  1021. /**
  1022. * Returns the italic angle of this <code>Font</code>.
  1023. * @return the angle of the ITALIC style of this <code>Font</code>.
  1024. */
  1025. public float getItalicAngle(){
  1026. double matrix[] = getMatrix();
  1027. return NativeFontWrapper.getItalicAngle(this, matrix, false, false);
  1028. }
  1029. /**
  1030. * Metrics from a font for layout of characters along a line
  1031. * and layout of set of lines.
  1032. */
  1033. private final class FontLineMetrics extends LineMetrics {
  1034. // package private fields
  1035. int numchars;
  1036. float ascent, descent, leading, height;
  1037. int baselineIndex;
  1038. float [] baselineOffsets;
  1039. float strikethroughOffset, strikethroughThickness;
  1040. float underlineOffset, underlineThickness;
  1041. public final int getNumChars() {
  1042. return numchars;
  1043. }
  1044. public final float getAscent() {
  1045. return ascent;
  1046. }
  1047. public final float getDescent() {
  1048. return descent;
  1049. }
  1050. public final float getLeading() {
  1051. return leading;
  1052. }
  1053. public final float getHeight() {
  1054. return height;
  1055. }
  1056. public final int getBaselineIndex() {
  1057. return baselineIndex;
  1058. }
  1059. public final float[] getBaselineOffsets() {
  1060. return baselineOffsets;
  1061. }
  1062. public final float getStrikethroughOffset() {
  1063. return strikethroughOffset;
  1064. }
  1065. public final float getStrikethroughThickness() {
  1066. return strikethroughThickness;
  1067. }
  1068. public final float getUnderlineOffset() {
  1069. return underlineOffset;
  1070. }
  1071. public final float getUnderlineThickness() {
  1072. return underlineThickness;
  1073. }
  1074. public final boolean equals(Object rhs) {
  1075. if (rhs != null) {
  1076. if (this == rhs) {
  1077. return true;
  1078. }
  1079. try {
  1080. FontLineMetrics rlm = (FontLineMetrics)rhs;
  1081. // does not include numchars, which should never have been here anyway
  1082. return ascent == rlm.ascent
  1083. && descent == rlm.descent
  1084. && leading == rlm.leading
  1085. && baselineIndex == rlm.baselineIndex
  1086. && baselineOffsets[0] == rlm.baselineOffsets[0]
  1087. && baselineOffsets[1] == rlm.baselineOffsets[1]
  1088. && baselineOffsets[2] == rlm.baselineOffsets[2]
  1089. && strikethroughOffset == rlm.strikethroughOffset
  1090. && strikethroughThickness == rlm.strikethroughThickness
  1091. && underlineOffset == rlm.underlineOffset
  1092. && underlineThickness == rlm.underlineThickness;
  1093. }
  1094. catch (ClassCastException e) {
  1095. }
  1096. }
  1097. return false;
  1098. }
  1099. }
  1100. /**
  1101. * Checks whether or not this <code>Font</code> has uniform
  1102. * line metrics. A logical <code>Font</code> might be a
  1103. * composite font, which means that it is composed of different
  1104. * physical fonts to cover different code ranges. Each of these
  1105. * fonts might have different <code>LineMetrics</code>. If the
  1106. * logical <code>Font</code> is a single
  1107. * font then the metrics would be uniform.
  1108. * @return <code>true</code> if this <code>Font</code> has
  1109. * uniform line metrics; <code>false</code> otherwise.
  1110. */
  1111. public boolean hasUniformLineMetrics() {
  1112. return false; // REMIND: always safe, but prevents caller optimize
  1113. }
  1114. private FontLineMetrics defaultLineMetrics(FontRenderContext frc) {
  1115. FontLineMetrics flm = new FontLineMetrics();
  1116. double [] matrix = getMatrix();
  1117. float [] metrics = new float[4];
  1118. NativeFontWrapper.getFontMetrics(this, matrix,
  1119. frc.isAntiAliased(),
  1120. frc.usesFractionalMetrics(),
  1121. metrics);
  1122. flm.ascent = metrics[0];
  1123. flm.descent = metrics[1];
  1124. flm.leading = metrics[2];
  1125. flm.height = metrics[0] + metrics[1] + metrics[2];
  1126. flm.baselineIndex = 0;
  1127. flm.baselineOffsets = new float[3];
  1128. flm.baselineOffsets[0] = 0;
  1129. flm.strikethroughOffset = -(flm.ascent / 3.0f);
  1130. flm.strikethroughThickness = pointSize / 12.0f;
  1131. flm.underlineOffset = 0f;
  1132. flm.underlineThickness = pointSize / 12.0f;
  1133. return flm;
  1134. }
  1135. /**
  1136. * Returns a {@link LineMetrics} object created with the specified
  1137. * <code>String</code> and {@link FontRenderContext}.
  1138. * @param str the specified <code>String</code>
  1139. * @param frc the specified <code>FontRenderContext</code>
  1140. * @return a <code>LineMetrics</code> object created with the
  1141. * specified <code>String</code> and {@link FontRenderContext}.
  1142. */
  1143. public LineMetrics getLineMetrics( String str, FontRenderContext frc) {
  1144. FontLineMetrics flm = defaultLineMetrics(frc);
  1145. flm.numchars = str.length();
  1146. return flm;
  1147. }
  1148. /**
  1149. * Returns a <code>LineMetrics</code> object created with the
  1150. * specified arguments.
  1151. * @param str the specified <code>String</code>
  1152. * @param beginIndex the initial offset of <code>str</code>
  1153. * @param limit the end offset of <code>str</code>
  1154. * @param frc the specified <code>FontRenderContext</code>
  1155. * @return a <code>LineMetrics</code> object created with the
  1156. * specified arguments.
  1157. */
  1158. public LineMetrics getLineMetrics( String str,
  1159. int beginIndex, int limit,
  1160. FontRenderContext frc) {
  1161. FontLineMetrics flm = defaultLineMetrics(frc);
  1162. int numChars = limit - beginIndex;
  1163. flm.numchars = (numChars < 0)? 0: numChars;
  1164. return flm;
  1165. }
  1166. /**
  1167. * Returns a <code>LineMetrics</code> object created with the
  1168. * specified arguments.
  1169. * @param chars an array of characters
  1170. * @param beginIndex the initial offset of <code>chars</code>
  1171. * @param limit the end offset of <code>chars</code>
  1172. * @param frc the specified <code>FontRenderContext</code>
  1173. * @return a <code>LineMetrics</code> object created with the
  1174. * specified arguments.
  1175. */
  1176. public LineMetrics getLineMetrics(char [] chars,
  1177. int beginIndex, int limit,
  1178. FontRenderContext frc) {
  1179. FontLineMetrics flm = defaultLineMetrics(frc);
  1180. int numChars = limit - beginIndex;
  1181. flm.numchars = (numChars < 0)? 0: numChars;
  1182. return flm;
  1183. }
  1184. /**
  1185. * Returns a <code>LineMetrics</code> object created with the
  1186. * specified arguments.
  1187. * @param ci the specified <code>CharacterIterator</code>
  1188. * @param beginIndex the initial offset in <code>ci</code>
  1189. * @param limit the end offset of <code>ci</code>
  1190. * @param frc the specified <code>FontRenderContext</code>
  1191. * @return a <code>LineMetrics</code> object created with the
  1192. * specified arguments.
  1193. */
  1194. public LineMetrics getLineMetrics(CharacterIterator ci,
  1195. int beginIndex, int limit,
  1196. FontRenderContext frc) {
  1197. FontLineMetrics flm = defaultLineMetrics(frc);
  1198. int numChars = limit - beginIndex;
  1199. flm.numchars = (numChars < 0)? 0: numChars;
  1200. return flm;
  1201. }
  1202. /**
  1203. * Returns the bounds of the specified <code>String</code> in the
  1204. * specified <code>FontRenderContext</code>. The bounds is used
  1205. * to layout the <code>String</code>.
  1206. * @param str the specified <code>String</code>
  1207. * @param frc the specified <code>FontRenderContext</code>
  1208. * @return a {@link Rectangle2D} that is the bounding box of the
  1209. * specified <code>String</code> in the specified
  1210. * <code>FontRenderContext</code>.
  1211. * @see FontRenderContext
  1212. * @see Font#createGlyphVector
  1213. * @since JDK1.2
  1214. */
  1215. public Rectangle2D getStringBounds( String str, FontRenderContext frc) {
  1216. char[] array = str.toCharArray();
  1217. return getStringBounds(array, 0, array.length, frc);
  1218. }
  1219. /**
  1220. * Returns the bounds of the specified <code>String</code> in the
  1221. * specified <code>FontRenderContext</code>. The bounds is used
  1222. * to layout the <code>String</code>.
  1223. * @param str the specified <code>String</code>
  1224. * @param beginIndex the initial offset of <code>str</code>
  1225. * @param limit the end offset of <code>str</code>
  1226. * @param frc the specified <code>FontRenderContext</code>
  1227. * @return a <code>Rectangle2D</code> that is the bounding box of the
  1228. * specified <code>String</code> in the specified
  1229. * <code>FontRenderContext</code>.
  1230. * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
  1231. * less than zero, or <code>limit</code> is greater than the
  1232. * length of <code>str</code>, or <code>beginIndex</code>
  1233. * is greater than <code>limit</code>.
  1234. * @see FontRenderContext
  1235. * @see Font#createGlyphVector
  1236. * @since JDK1.2
  1237. */
  1238. public Rectangle2D getStringBounds( String str,
  1239. int beginIndex, int limit,
  1240. FontRenderContext frc) {
  1241. String substr = str.substring(beginIndex, limit);
  1242. return getStringBounds(substr, frc);
  1243. }
  1244. /**
  1245. * Returns the bounds of the specified array of characters
  1246. * in the specified <code>FontRenderContext</code>.
  1247. * The bounds is used to layout the <code>String</code>
  1248. * created with the specified array of characters,
  1249. * <code>beginIndex</code> and <code>limit</code>.
  1250. * @param chars an array of characters
  1251. * @param beginIndex the initial offset in the array of
  1252. * characters
  1253. * @param limit the end offset in the array of characters
  1254. * @param frc the specified <code>FontRenderContext</code>
  1255. * @return a <code>Rectangle2D</code> that is the bounding box of the
  1256. * specified array of characters in the specified
  1257. * <code>FontRenderContext</code>.
  1258. * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
  1259. * less than zero, or <code>limit</code> is greater than the
  1260. * length of <code>chars</code>, or <code>beginIndex</code>
  1261. * is greater than <code>limit</code>.
  1262. * @see FontRenderContext
  1263. * @see Font#createGlyphVector
  1264. * @since JDK1.2
  1265. */
  1266. public Rectangle2D getStringBounds(char [] chars,
  1267. int beginIndex, int limit,
  1268. FontRenderContext frc) {
  1269. // this code should be in textlayout
  1270. // quick check for simple text, assume GV ok to use if simple
  1271. boolean simple = true;
  1272. for (int i = beginIndex; i < limit; ++i) {
  1273. char c = chars[i];
  1274. if (c >= '\u0590' && c <= '\u206f') {
  1275. simple = false;
  1276. break;
  1277. }
  1278. }
  1279. if (simple) {
  1280. GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex, limit - beginIndex, frc);
  1281. return gv.getLogicalBounds();
  1282. } else {
  1283. // need char array constructor on textlayout
  1284. String str = new String(chars, beginIndex, limit - beginIndex);
  1285. TextLayout tl = new TextLayout(str, this, frc);
  1286. return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(), tl.getDescent() + tl.getLeading());
  1287. }
  1288. }
  1289. /**
  1290. * Returns the bounds of the characters indexed in the specified
  1291. * {@link CharacterIterator} in the
  1292. * specified <code>FontRenderContext</code>. The bounds is used
  1293. * to layout the <code>String</code>.
  1294. * @param ci the specified <code>CharacterIterator</code>
  1295. * @param beginIndex the initial offset in <code>ci</code>
  1296. * @param limit the end offset in <code>ci</code>
  1297. * @param frc the specified <code>FontRenderContext</code>
  1298. * @return a <code>Rectangle2D</code> that is the bounding box of the
  1299. * characters indexed in the specified <code>CharacterIterator</code>
  1300. * in the specified <code>FontRenderContext</code>.
  1301. * @see FontRenderContext
  1302. * @see Font#createGlyphVector
  1303. * @since JDK1.2
  1304. * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
  1305. * less than the start index of <code>ci</code>, or
  1306. * <code>limit</code> is greater than the end index of
  1307. * <code>ci</code>, or <code>beginIndex</code> is greater
  1308. * than <code>limit</code>
  1309. */
  1310. public Rectangle2D getStringBounds(CharacterIterator ci,
  1311. int beginIndex, int limit,
  1312. FontRenderContext frc) {
  1313. int start = ci.getBeginIndex();
  1314. int end = ci.getEndIndex();
  1315. if (beginIndex >= start
  1316. && limit >= beginIndex
  1317. && limit <= end) {
  1318. char[] arr = new char[limit - beginIndex];
  1319. ci.setIndex(beginIndex);
  1320. for(int idx = 0; idx < arr.length; idx++) {
  1321. arr[idx] = ci.current();
  1322. ci.next();
  1323. }
  1324. return getStringBounds(arr,0,arr.length,frc);
  1325. }
  1326. throw new IllegalArgumentException("beginIndex or limit out of bounds of iterator");
  1327. }
  1328. /**
  1329. * Returns the bounds for the character with the maximum
  1330. * bounds as defined in the specified <code>FontRenderContext</code>.
  1331. * @param frc the specified <code>FontRenderContext</code>
  1332. * @return a <code>Rectangle2D</code> that is the bounding box
  1333. * for the character with the maximum bounds.
  1334. */
  1335. public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
  1336. double [] matrix = getMatrix();
  1337. float [] metrics = new float[4];
  1338. NativeFontWrapper.getFontMetrics(this, matrix,
  1339. frc.isAntiAliased(),
  1340. frc.usesFractionalMetrics(),
  1341. metrics);
  1342. return new Rectangle2D.Float(0, -metrics[0],
  1343. metrics[3],
  1344. metrics[0] + metrics[1] + metrics[2]);
  1345. }
  1346. /**
  1347. * Returns a new {@link GlyphVector} object created with the
  1348. * specified <code>String</code> and the specified
  1349. * <code>FontRenderContext</code>.
  1350. * @param frc the specified <code>FontRenderContext</code>
  1351. * @param str the specified <code>String</code>
  1352. * @return a new <code>GlyphVector</code> created with the
  1353. * specified <code>String</code> and the specified
  1354. * <code>FontRenderContext</code>.
  1355. */
  1356. public GlyphVector createGlyphVector(FontRenderContext frc, String str)
  1357. {
  1358. return (GlyphVector)new StandardGlyphVector(this, str, frc);
  1359. }
  1360. /**
  1361. * Returns a new <code>GlyphVector</code> object created with the
  1362. * specified array of characters and the specified
  1363. * <code>FontRenderContext</code>.
  1364. * @param frc the specified <code>FontRenderContext</code>
  1365. * @param chars the specified array of characters
  1366. * @return a new <code>GlyphVector</code> created with the
  1367. * specified array of characters and the specified
  1368. * <code>FontRenderContext</code>.
  1369. */
  1370. public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars)
  1371. {
  1372. return (GlyphVector)new StandardGlyphVector(this, chars, frc);
  1373. }
  1374. /**
  1375. * Returns a new <code>GlyphVector</code> object created with the
  1376. * specified <code>CharacterIterator</code> and the specified
  1377. * <code>FontRenderContext</code>.
  1378. * @param frc the specified <code>FontRenderContext</code>
  1379. * @param ci the specified <code>CharacterIterator</code>
  1380. * @return a new <code>GlyphVector</code> created with the
  1381. * specified <code>CharacterIterator</code> and the specified
  1382. * <code>FontRenderContext</code>.
  1383. */
  1384. public GlyphVector createGlyphVector( FontRenderContext frc,
  1385. CharacterIterator ci)
  1386. {
  1387. return (GlyphVector)new StandardGlyphVector(this, ci, frc);
  1388. }
  1389. /**
  1390. * Returns a new <code>GlyphVector</code> object created with the
  1391. * specified integer array and the specified
  1392. * <code>FontRenderContext</code>.
  1393. * @param frc the specified <code>FontRenderContext</code>
  1394. * @param glyphcodes the specified integer array
  1395. * @return a new <code>GlyphVector</code> created with the
  1396. * specified integer array and the specified
  1397. * <code>FontRenderContext</code>.
  1398. */
  1399. public GlyphVector createGlyphVector( FontRenderContext frc,
  1400. int [] glyphCodes)
  1401. {
  1402. return (GlyphVector)new StandardGlyphVector(this, glyphCodes, frc);
  1403. }
  1404. private static Hashtable ffApply(String name, Map attributes) {
  1405. Hashtable rval = new Hashtable(attributes);
  1406. rval.put(TextAttribute.FAMILY, name);
  1407. return rval;
  1408. }
  1409. private static Hashtable ffApply(AffineTransform trans, Map attributes) {
  1410. Hashtable rval = new Hashtable(attributes);
  1411. rval.put(TextAttribute.TRANSFORM, new TransformAttribute(trans));
  1412. return rval;
  1413. }
  1414. private static Hashtable ffApply(int style, Map attributes) {
  1415. Hashtable rval = new Hashtable(attributes);
  1416. if ((style & BOLD) != 0) {
  1417. rval.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
  1418. } else {
  1419. rval.remove(TextAttribute.WEIGHT);
  1420. }
  1421. if ((style & ITALIC) != 0) {
  1422. rval.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
  1423. } else {
  1424. rval.remove(TextAttribute.POSTURE);
  1425. }
  1426. return rval;
  1427. }
  1428. private static Hashtable ffApply(float size, Map attributes) {
  1429. Hashtable rval = new Hashtable(attributes);
  1430. rval.put(TextAttribute.SIZE, new Float(size));
  1431. return rval;
  1432. }
  1433. private static Hashtable ffApply(String name, int style,
  1434. float size, Map attributes)
  1435. {
  1436. return ffApply(name, ffApply(style, ffApply(size, attributes)));
  1437. }
  1438. /*
  1439. * Initialize JNI field and method IDs
  1440. */
  1441. private static native void initIDs();
  1442. private native void pDispose();
  1443. /**
  1444. * Disposes the native <code>Font</code> object.
  1445. */
  1446. protected void finalize() throws Throwable {
  1447. if (this.peer != null) {
  1448. pDispose();
  1449. }
  1450. super.finalize();
  1451. }
  1452. // Return a Microsoft LCID from the given Locale.
  1453. // Used when getting localized font data.
  1454. private static final String systemBundle =
  1455. "java.text.resources.LocaleElements";
  1456. private short getLcidFromLocale(Locale l) {
  1457. short lcid = 0x0409; // US English - default
  1458. // optimize for common case:
  1459. if (l.equals(Locale.US)) {
  1460. return lcid;
  1461. }
  1462. String lcidAsString;
  1463. try {
  1464. ResourceBundle bundle = ResourceBundle.getBundle(systemBundle, l);
  1465. lcidAsString = bundle.getString("LocaleID");
  1466. }
  1467. catch(MissingResourceException e) {
  1468. return lcid;
  1469. }
  1470. try {
  1471. lcid = (short) Integer.parseInt(lcidAsString, 16);
  1472. }
  1473. catch(NumberFormatException e) {
  1474. }
  1475. return lcid;
  1476. }
  1477. }