home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / awt / Font.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  52.7 KB  |  1,546 lines  |  [TEXT/CWIE]

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