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