KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > Font


1 /*
2  * @(#)Font.java 1.201 05/11/02
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt;
9
10 import java.awt.font.FontRenderContext JavaDoc;
11 import java.awt.font.GlyphVector JavaDoc;
12 import java.awt.font.LineMetrics JavaDoc;
13 import java.awt.font.TextAttribute JavaDoc;
14 import java.awt.font.TextLayout JavaDoc;
15 import java.awt.font.TransformAttribute JavaDoc;
16 import java.awt.geom.AffineTransform JavaDoc;
17 import java.awt.geom.Rectangle2D JavaDoc;
18 import java.awt.peer.FontPeer;
19 import java.io.*;
20 import java.lang.ref.SoftReference JavaDoc;
21 import java.text.AttributedCharacterIterator.Attribute;
22 import java.text.CharacterIterator JavaDoc;
23 import java.text.StringCharacterIterator JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Hashtable JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28 import sun.font.StandardGlyphVector;
29 import sun.java2d.FontSupport;
30
31 import sun.font.Font2D;
32 import sun.font.Font2DHandle;
33 import sun.font.FontManager;
34 import sun.font.GlyphLayout;
35 import sun.font.FontLineMetrics;
36 import sun.font.CoreMetrics;
37
38 /**
39  * The <code>Font</code> class represents fonts, which are used to
40  * render text in a visible way.
41  * A font provides the information needed to map sequences of
42  * <em>characters</em> to sequences of <em>glyphs</em>
43  * and to render sequences of glyphs on <code>Graphics</code> and
44  * <code>Component</code> objects.
45  *
46  * <h4>Characters and Glyphs</h4>
47  *
48  * A <em>character</em> is a symbol that represents an item such as a letter,
49  * a digit, or punctuation in an abstract way. For example, <code>'g'</code>,
50  * <font size=-1>LATIN SMALL LETTER G</font>, is a character.
51  * <p>
52  * A <em>glyph</em> is a shape used to render a character or a sequence of
53  * characters. In simple writing systems, such as Latin, typically one glyph
54  * represents one character. In general, however, characters and glyphs do not
55  * have one-to-one correspondence. For example, the character '&aacute;'
56  * <font size=-1>LATIN SMALL LETTER A WITH ACUTE</font>, can be represented by
57  * two glyphs: one for 'a' and one for '&acute;'. On the other hand, the
58  * two-character string "fi" can be represented by a single glyph, an
59  * "fi" ligature. In complex writing systems, such as Arabic or the South
60  * and South-East Asian writing systems, the relationship between characters
61  * and glyphs can be more complicated and involve context-dependent selection
62  * of glyphs as well as glyph reordering.
63  *
64  * A font encapsulates the collection of glyphs needed to render a selected set
65  * of characters as well as the tables needed to map sequences of characters to
66  * corresponding sequences of glyphs.
67  *
68  * <h4>Physical and Logical Fonts</h4>
69  *
70  * The Java 2 platform distinguishes between two kinds of fonts:
71  * <em>physical</em> fonts and <em>logical</em> fonts.
72  * <p>
73  * <em>Physical</em> fonts are the actual font libraries containing glyph data
74  * and tables to map from character sequences to glyph sequences, using a font
75  * technology such as TrueType or PostScript Type 1.
76  * All implementations of the Java 2 platform must support TrueType fonts;
77  * support for other font technologies is implementation dependent.
78  * Physical fonts may use names such as Helvetica, Palatino, HonMincho, or
79  * any number of other font names.
80  * Typically, each physical font supports only a limited set of writing
81  * systems, for example, only Latin characters or only Japanese and Basic
82  * Latin.
83  * The set of available physical fonts varies between configurations.
84  * Applications that require specific fonts can bundle them and instantiate
85  * them using the {@link #createFont createFont} method.
86  * <p>
87  * <em>Logical</em> fonts are the five font families defined by the Java
88  * platform which must be supported by any Java runtime environment:
89  * Serif, SansSerif, Monospaced, Dialog, and DialogInput.
90  * These logical fonts are not actual font libraries. Instead, the logical
91  * font names are mapped to physical fonts by the Java runtime environment.
92  * The mapping is implementation and usually locale dependent, so the look
93  * and the metrics provided by them vary.
94  * Typically, each logical font name maps to several physical fonts in order to
95  * cover a large range of characters.
96  * <p>
97  * Peered AWT components, such as {@link Label Label} and
98  * {@link TextField TextField}, can only use logical fonts.
99  * <p>
100  * For a discussion of the relative advantages and disadvantages of using
101  * physical or logical fonts, see the
102  * <a HREF="http://java.sun.com/j2se/corejava/intl/reference/faqs/index.html#desktop-rendering">Internationalization FAQ</a>
103  * document.
104  *
105  * <h4>Font Faces and Names</h4>
106  *
107  * A <code>Font</code>
108  * can have many faces, such as heavy, medium, oblique, gothic and
109  * regular. All of these faces have similar typographic design.
110  * <p>
111  * There are three different names that you can get from a
112  * <code>Font</code> object. The <em>logical font name</em> is simply the
113  * name that was used to construct the font.
114  * The <em>font face name</em>, or just <em>font name</em> for
115  * short, is the name of a particular font face, like Helvetica Bold. The
116  * <em>family name</em> is the name of the font family that determines the
117  * typographic design across several faces, like Helvetica.
118  * <p>
119  * The <code>Font</code> class represents an instance of a font face from
120  * a collection of font faces that are present in the system resources
121  * of the host system. As examples, Arial Bold and Courier Bold Italic
122  * are font faces. There can be several <code>Font</code> objects
123  * associated with a font face, each differing in size, style, transform
124  * and font features.
125  * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method
126  * of the <code>GraphicsEnvironment</code> class returns an
127  * array of all font faces available in the system. These font faces are
128  * returned as <code>Font</code> objects with a size of 1, identity
129  * transform and default font features. These
130  * base fonts can then be used to derive new <code>Font</code> objects
131  * with varying sizes, styles, transforms and font features via the
132  * <code>deriveFont</code> methods in this class.
133  *
134  * @version 1.201, 11/02/05
135  */

136 public class Font implements java.io.Serializable JavaDoc
137 {
138    
139     static {
140         /* ensure that the necessary native libraries are loaded */
141     Toolkit.loadLibraries();
142         initIDs();
143     }
144
145     /**
146      * A map of font attributes available in this font.
147      * Attributes include things like ligatures and glyph substitution.
148      *
149      * @serial
150      * @see #getAttributes()
151      */

152     private Hashtable JavaDoc fRequestedAttributes;
153     
154     private static final Map JavaDoc EMPTY_MAP = new Hashtable JavaDoc(5, (float)0.9);
155     private static final TransformAttribute JavaDoc IDENT_TX_ATTRIBUTE =
156     new TransformAttribute JavaDoc(new AffineTransform JavaDoc());
157
158     /*
159      * Constants to be used for styles. Can be combined to mix
160      * styles.
161      */

162
163     /**
164      * The plain style constant.
165      */

166     public static final int PLAIN = 0;
167
168     /**
169      * The bold style constant. This can be combined with the other style
170      * constants (except PLAIN) for mixed styles.
171      */

172     public static final int BOLD = 1;
173
174     /**
175      * The italicized style constant. This can be combined with the other
176      * style constants (except PLAIN) for mixed styles.
177      */

178     public static final int ITALIC = 2;
179
180     /**
181      * The baseline used in most Roman scripts when laying out text.
182      */

183     public static final int ROMAN_BASELINE = 0;
184
185     /**
186      * The baseline used in ideographic scripts like Chinese, Japanese,
187      * and Korean when laying out text.
188      */

189     public static final int CENTER_BASELINE = 1;
190
191     /**
192      * The baseline used in Devanigiri and similar scripts when laying
193      * out text.
194      */

195     public static final int HANGING_BASELINE = 2;
196
197     /**
198      * Identify a font resource of type TRUETYPE.
199      * Used to specify a TrueType font resource to the
200      * {@link #createFont} method.
201      * @since 1.3
202      */

203
204     public static final int TRUETYPE_FONT = 0;
205
206     /**
207      * Identify a font resource of type TYPE1.
208      * Used to specify a Type1 font resource to the
209      * {@link #createFont} method.
210      * @since 1.5
211      */

212     public static final int TYPE1_FONT = 1;
213
214     /**
215      * The logical name of this <code>Font</code>, as passed to the
216      * constructor.
217      * @since JDK1.0
218      *
219      * @serial
220      * @see #getName
221      */

222     protected String JavaDoc name;
223
224     /**
225      * The style of this <code>Font</code>, as passed to the constructor.
226      * This style can be PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
227      * @since JDK1.0
228      *
229      * @serial
230      * @see #getStyle()
231      */

232     protected int style;
233
234     /**
235      * The point size of this <code>Font</code>, rounded to integer.
236      * @since JDK1.0
237      *
238      * @serial
239      * @see #getSize()
240      */

241     protected int size;
242
243     /**
244      * The point size of this <code>Font</code> in <code>float</code>.
245      *
246      * @serial
247      * @see #getSize()
248      * @see #getSize2D()
249      */

250     protected float pointSize;
251
252     /**
253      * The platform specific font information.
254      */

255     private transient FontPeer peer;
256     private transient long pData; // native JDK1.1 font pointer
257
private transient Font2DHandle font2DHandle;
258     private transient int superscript;
259     private transient float width = 1f;
260
261     /*
262      * If the origin of a Font is a created font then this attribute
263      * must be set on all derived fonts too.
264      */

265     private transient boolean createdFont = false;
266
267     // cached values - performance
268
private transient double[] matrix;
269     private transient boolean nonIdentityTx;
270
271     private static final AffineTransform JavaDoc identityTx = new AffineTransform JavaDoc();
272     /*
273      * JDK 1.1 serialVersionUID
274      */

275     private static final long serialVersionUID = -4206021311591459213L;
276
277     /**
278      * Gets the peer of this <code>Font</code>.
279      * @return the peer of the <code>Font</code>.
280      * @since JDK1.1
281      * @deprecated Font rendering is now platform independent.
282      */

283     @Deprecated JavaDoc
284     public FontPeer getPeer(){
285     return getPeer_NoClientCode();
286     }
287     // NOTE: This method is called by privileged threads.
288
// We implement this functionality in a package-private method
289
// to insure that it cannot be overridden by client subclasses.
290
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
291
final FontPeer getPeer_NoClientCode() {
292         if(peer == null) {
293             Toolkit JavaDoc tk = Toolkit.getDefaultToolkit();
294             this.peer = tk.getFontPeer(name, style);
295         }
296         return peer;
297     }
298
299     /* create this map only when requested - which may be rarely */
300     private Hashtable JavaDoc getRequestedAttributes() {
301     if (fRequestedAttributes == null) {
302         fRequestedAttributes = new Hashtable JavaDoc(7, (float)0.9);
303             fRequestedAttributes.put(TextAttribute.TRANSFORM,
304                      IDENT_TX_ATTRIBUTE);
305             fRequestedAttributes.put(TextAttribute.FAMILY, name);
306             fRequestedAttributes.put(TextAttribute.SIZE, new Float JavaDoc(size));
307         fRequestedAttributes.put(TextAttribute.WEIGHT,
308                      (style & BOLD) != 0 ?
309                      TextAttribute.WEIGHT_BOLD :
310                      TextAttribute.WEIGHT_REGULAR);
311         fRequestedAttributes.put(TextAttribute.POSTURE,
312                      (style & ITALIC) != 0 ?
313                      TextAttribute.POSTURE_OBLIQUE :
314                      TextAttribute.POSTURE_REGULAR);
315             fRequestedAttributes.put(TextAttribute.SUPERSCRIPT,
316                                      new Integer JavaDoc(superscript));
317             fRequestedAttributes.put(TextAttribute.WIDTH,
318                                      new Float JavaDoc(width));
319     }
320     return fRequestedAttributes;
321     }
322
323     private void initializeFont(Hashtable JavaDoc attributes) {
324         if (attributes != null) {
325         Object JavaDoc obj = attributes.get(TextAttribute.TRANSFORM);
326         if (obj instanceof TransformAttribute JavaDoc) {
327         nonIdentityTx = !((TransformAttribute JavaDoc)obj).isIdentity();
328         } else if (obj instanceof AffineTransform JavaDoc) {
329         nonIdentityTx = !((AffineTransform JavaDoc)obj).isIdentity();
330         }
331
332             obj = attributes.get(TextAttribute.SUPERSCRIPT);
333             if (obj instanceof Integer JavaDoc) {
334                 superscript = ((Integer JavaDoc)obj).intValue();
335
336                 // !!! always synthesize superscript
337
nonIdentityTx |= superscript != 0;
338             }
339
340             obj = attributes.get(TextAttribute.WIDTH);
341             if (obj instanceof Integer JavaDoc) {
342                 width = ((Float JavaDoc)obj).floatValue();
343
344                 // !!! always synthesize width
345
nonIdentityTx |= width != 1;
346             }
347         }
348     }
349
350     private Font2D getFont2D() {
351     if (FontManager.usingPerAppContextComposites &&
352         font2DHandle != null &&
353         font2DHandle.font2D instanceof sun.font.CompositeFont &&
354         ((sun.font.CompositeFont)(font2DHandle.font2D)).isStdComposite()) {
355         return FontManager.findFont2D(name, style,
356                       FontManager.LOGICAL_FALLBACK);
357     } else if (font2DHandle == null) {
358         font2DHandle =
359         FontManager.findFont2D(name, style,
360                        FontManager.LOGICAL_FALLBACK).handle;
361     }
362     /* Do not cache the de-referenced font2D. It must be explicitly
363      * de-referenced to pick up a valid font in the event that the
364      * original one is marked invalid
365      */

366     return font2DHandle.font2D;
367     }
368
369     /*
370      * If this font was created by "createFont" return its handle,
371      * else return null. created fonts always have a non-null handle.
372      * The test for CompositeFont is because the boolean "createdFont"
373      * is overloaded to indicate any font that needs to copy its handle
374      * and that doesn't apply to true created fonts.
375      */

376     private Font2DHandle getFont2DHandleForCreatedFont() {
377         if (font2DHandle != null && createdFont &&
378             !(font2DHandle.font2D instanceof sun.font.CompositeFont)) {
379             return font2DHandle;
380         } else {
381             return null;
382         }
383     }
384
385     /**
386      * Creates a new <code>Font</code> from the specified name, style and
387      * point size.
388      * <p>
389      * The font name can be a font face name or a font family name.
390      * It is used together with the style to find an appropriate font face.
391      * When a font family name is specified, the style argument is used to
392      * select the most appropriate face from the family. When a font face
393      * name is specified, the face's style and the style argument are
394      * merged to locate the best matching font from the same family.
395      * For example if face name "Arial Bold" is specified with style
396      * <code>Font.ITALIC</code>, the font system looks for a face in the
397      * "Arial" family that is bold and italic, and may associate the font
398      * instance with the physical font face "Arial Bold Italic".
399      * The style argument is merged with the specified face's style, not
400      * added or subtracted.
401      * This means, specifying a bold face and a bold style does not
402      * double-embolden the font, and specifying a bold face and a plain
403      * style does not lighten the font.
404      * <p>
405      * If no face for the requested style can be found, the font system
406      * may apply algorithmic styling to achieve the desired style.
407      * For example, if <code>ITALIC</code> is requested, but no italic
408      * face is available, glyphs from the plain face may be algorithmically
409      * obliqued (slanted).
410      * <p>
411      * Font name lookup is case insensitive, using the case folding
412      * rules of the US locale.
413      *
414      * @param name the font name. This can be a font face name or a font
415      * family name, and may represent either a logical font or a physical
416      * font found in this <code>GraphicsEnvironment</code>.
417      * The family names for logical fonts are: Dialog, DialogInput,
418      * Monospaced, Serif, or SansSerif. If <code>name</code> is
419      * <code>null</code>, the <em>logical font name</em> of the new
420      * <code>Font</code> as returned by <code>getName()</code>is set to
421      * the name "Default".
422      * @param style the style constant for the <code>Font</code>
423      * The style argument is an integer bitmask that may
424      * be PLAIN, or a bitwise union of BOLD and/or ITALIC
425      * (for example, ITALIC or BOLD|ITALIC).
426      * If the style argument does not conform to one of the expected
427      * integer bitmasks then the style is set to PLAIN.
428      * @param size the point size of the <code>Font</code>
429      * @see GraphicsEnvironment#getAllFonts
430      * @see GraphicsEnvironment#getAvailableFontFamilyNames
431      * @since JDK1.0
432      */

433     public Font(String JavaDoc name, int style, int size) {
434     this.name = (name != null) ? name : "Default";
435     this.style = (style & ~0x03) == 0 ? style : 0;
436     this.size = size;
437         this.pointSize = size;
438     }
439
440     private Font(String JavaDoc name, int style, float sizePts) {
441     this.name = (name != null) ? name : "Default";
442     this.style = (style & ~0x03) == 0 ? style : 0;
443     this.size = (int)(sizePts + 0.5);
444         this.pointSize = sizePts;
445     }
446
447     /* used to implement Font.createFont */
448     private Font(File fontFile, int fontFormat, boolean isCopy)
449         throws FontFormatException JavaDoc {
450     this.createdFont = true;
451     /* Font2D instances created by this method track their font file
452      * so that when the Font2D is GC'd it can also remove the file.
453      */

454     this.font2DHandle =
455         FontManager.createFont2D(fontFile, fontFormat, isCopy).handle;
456     this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
457     this.style = Font.PLAIN;
458     this.size = 1;
459     this.pointSize = 1f;
460     }
461
462     private Font(Map JavaDoc attributes, boolean created, Font2DHandle handle) {
463     this.createdFont = created;
464     /* Fonts created from a stream will use the same font2D instance
465      * as the parent.
466      */

467     if (created) {
468         this.font2DHandle = handle;
469     }
470     initFromMap(attributes);
471     }
472
473     /**
474      * Creates a new <code>Font</code> with the specified attributes.
475      * This <code>Font</code> only recognizes keys defined in
476      * {@link TextAttribute} as attributes. If <code>attributes</code>
477      * is <code>null</code>, a new <code>Font</code> is initialized
478      * with default attributes.
479      * @param attributes the attributes to assign to the new
480      * <code>Font</code>, or <code>null</code>
481      */

482     public Font(Map JavaDoc<? extends Attribute JavaDoc, ?> attributes) {
483     initFromMap(attributes);
484     }
485
486
487     private void initFromMap(Map JavaDoc attributes) {
488     this.name = "Dialog";
489         this.pointSize = 12;
490         this.size = 12;
491
492         if((attributes != null) &&
493            (!attributes.equals(EMPTY_MAP)))
494         {
495             Object JavaDoc obj;
496             fRequestedAttributes = new Hashtable JavaDoc(attributes);
497             if ((obj = attributes.get(TextAttribute.FAMILY)) != null) {
498                 this.name = (String JavaDoc)obj;
499             }
500
501             if ((obj = attributes.get(TextAttribute.WEIGHT)) != null) {
502                 if(obj.equals(TextAttribute.WEIGHT_BOLD)) {
503                     this.style |= BOLD;
504                 }
505             }
506
507             if ((obj = attributes.get(TextAttribute.POSTURE)) != null) {
508                 if(obj.equals(TextAttribute.POSTURE_OBLIQUE)) {
509                     this.style |= ITALIC;
510                 }
511             }
512
513             if ((obj = attributes.get(TextAttribute.SIZE)) != null) {
514                 this.pointSize = ((Float JavaDoc)obj).floatValue();
515                 this.size = (int)(this.pointSize + 0.5);
516             }
517
518             if ((obj = attributes.get(TextAttribute.TRANSFORM)) != null) {
519         if (obj instanceof TransformAttribute JavaDoc) {
520             nonIdentityTx = !((TransformAttribute JavaDoc)obj).isIdentity();
521         } else if (obj instanceof AffineTransform JavaDoc) {
522             nonIdentityTx = !((AffineTransform JavaDoc)obj).isIdentity();
523         }
524         }
525
526             if ((obj = attributes.get(TextAttribute.SUPERSCRIPT)) != null) {
527                 if (obj instanceof Integer JavaDoc) {
528                     superscript = ((Integer JavaDoc)obj).intValue();
529                     nonIdentityTx |= superscript != 0;
530                 }
531             }
532
533             if ((obj = attributes.get(TextAttribute.WIDTH)) != null) {
534                 if (obj instanceof Float JavaDoc) {
535                     width = ((Float JavaDoc)obj).floatValue();
536                     nonIdentityTx |= width != 1;
537                 }
538             }
539         }
540     }
541
542      /**
543      * Returns a <code>Font</code> appropriate to this attribute set.
544      *
545      * @param attributes the attributes to assign to the new
546      * <code>Font</code>
547      * @return a new <code>Font</code> created with the specified
548      * attributes
549      * @since 1.2
550      * @see java.awt.font.TextAttribute
551      */

552     public static Font JavaDoc getFont(Map JavaDoc<? extends Attribute JavaDoc, ?> attributes) {
553         Font JavaDoc font = (Font JavaDoc)attributes.get(TextAttribute.FONT);
554         if (font != null) {
555             return font;
556         }
557
558     return get(new Key(attributes));
559     }
560
561     private static SoftReference JavaDoc cacheRef = new SoftReference JavaDoc(new HashMap JavaDoc());
562     private static Font JavaDoc get(Key key) {
563     Font JavaDoc f = null;
564     Map JavaDoc cache = (Map JavaDoc)cacheRef.get();
565     if (cache == null) {
566         cache = new HashMap JavaDoc();
567         cacheRef = new SoftReference JavaDoc(cache);
568     } else {
569         f = (Font JavaDoc)cache.get(key);
570     }
571
572     if (f == null) {
573         f = new Font JavaDoc(key.attrs);
574         cache.put(key, f);
575     }
576
577     return f;
578     }
579
580     // ideally we would construct a font directly from a key, and not
581
// bother to keep the map around for this. That ought to be a bit
582
// faster than picking out the params from the Map again, but the
583
// cache ought to hide this overhead, so I'll skip it for now.
584

585     private static class Key {
586     String JavaDoc family = "Dialog"; // defaults chosen to match Font implementation
587
float weight = 1.0f;
588     float posture = 0.0f;
589     float size = 12.0f;
590         int superscript = 0;
591         float width = 1.0f;
592     double[] txdata = null; // identity
593

594     Map JavaDoc attrs;
595     int hashCode = 0;
596
597     Key(Map JavaDoc map) {
598         attrs = map;
599
600         Object JavaDoc o = map.get(TextAttribute.FAMILY);
601         if (o != null) {
602         family = (String JavaDoc)o;
603         }
604         hashCode = family.hashCode();
605
606         o = map.get(TextAttribute.WEIGHT);
607         if (o != null && o != TextAttribute.WEIGHT_REGULAR) {
608         // ugh, force to the only values we understand
609
// weight is either bold, or it's not...
610
float xweight = ((Float JavaDoc)o).floatValue();
611         if (xweight == TextAttribute.WEIGHT_BOLD.floatValue()) {
612             weight = xweight;
613             hashCode = (hashCode << 3) ^ Float.floatToIntBits(weight);
614         }
615         }
616
617         o = map.get(TextAttribute.POSTURE);
618         if (o != null && o != TextAttribute.POSTURE_REGULAR) {
619         // ugh, same problem as with weight
620
float xposture = ((Float JavaDoc)o).floatValue();
621         if (xposture == TextAttribute.POSTURE_OBLIQUE.floatValue()) {
622             posture = xposture;
623             hashCode = (hashCode << 3) ^ Float.floatToIntBits(posture);
624         }
625         }
626
627         o = map.get(TextAttribute.SIZE);
628         if (o != null) {
629         size = ((Float JavaDoc)o).floatValue();
630         if (size != 12.0f) {
631             hashCode = (hashCode << 3) ^ Float.floatToIntBits(size);
632         }
633         }
634
635         o = map.get(TextAttribute.TRANSFORM);
636         if (o != null) {
637         AffineTransform JavaDoc tx = null;
638         if (o instanceof TransformAttribute JavaDoc) {
639             TransformAttribute JavaDoc ta = (TransformAttribute JavaDoc)o;
640             if (!ta.isIdentity()) {
641             tx = ta.getTransform();
642             }
643         } else if (o instanceof AffineTransform JavaDoc) {
644             AffineTransform JavaDoc at = (AffineTransform JavaDoc)o;
645             if (!at.isIdentity()) {
646             tx = at;
647             }
648         }
649         if (tx != null) {
650             txdata = new double[6];
651             tx.getMatrix(txdata);
652             hashCode = (hashCode << 3) ^ new Double JavaDoc(txdata[0]).hashCode();
653         }
654         }
655
656             o = map.get(TextAttribute.SUPERSCRIPT);
657             if (o != null) {
658                 if (o instanceof Integer JavaDoc) {
659                     superscript = ((Integer JavaDoc)o).intValue();
660                     hashCode = hashCode << 3 ^ superscript;
661                 }
662             }
663
664             o = map.get(TextAttribute.WIDTH);
665             if (o != null) {
666                 if (o instanceof Float JavaDoc) {
667                     width = ((Float JavaDoc)o).floatValue();
668                     hashCode = hashCode << 3 ^ Float.floatToIntBits(width);
669                 }
670             }
671     }
672
673     public int hashCode() {
674         return hashCode;
675     }
676
677     public boolean equals(Object JavaDoc rhs) {
678         Key rhskey = (Key)rhs;
679         if (this.hashCode == rhskey.hashCode &&
680         this.size == rhskey.size &&
681         this.weight == rhskey.weight &&
682         this.posture == rhskey.posture &&
683                 this.superscript == rhskey.superscript &&
684                 this.width == rhskey.width &&
685         this.family.equals(rhskey.family) &&
686         ((this.txdata == null) == (rhskey.txdata == null))) {
687         
688         if (this.txdata != null) {
689             for (int i = 0; i < this.txdata.length; ++i) {
690             if (this.txdata[i] != rhskey.txdata[i]) {
691                 return false;
692             }
693             }
694         }
695         return true;
696         }
697         return false;
698     }
699     }
700     
701
702   /**
703    * Returns a new <code>Font</code> using the specified font type
704    * and input data. The new <code>Font</code> is
705    * created with a point size of 1 and style {@link #PLAIN PLAIN}.
706    * This base font can then be used with the <code>deriveFont</code>
707    * methods in this class to derive new <code>Font</code> objects with
708    * varying sizes, styles, transforms and font features. This
709    * method does not close the {@link InputStream}.
710    * @param fontFormat the type of the <code>Font</code>, which is
711    * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is specified.
712    * or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is specified.
713    * @param fontStream an <code>InputStream</code> object representing the
714    * input data for the font.
715    * @return a new <code>Font</code> created with the specified font type.
716    * @throws IllegalArgumentException if <code>fontFormat</code> is not
717    * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
718    * @throws FontFormatException if the <code>fontStream</code> data does
719    * not contain the required font tables for the specified format.
720    * @throws IOException if the <code>fontStream</code>
721    * cannot be completely read.
722    * @since 1.3
723    */

724     public static Font JavaDoc createFont(int fontFormat, InputStream fontStream)
725     throws java.awt.FontFormatException JavaDoc, java.io.IOException JavaDoc {
726
727     if (fontFormat != Font.TRUETYPE_FONT &&
728         fontFormat != Font.TYPE1_FONT) {
729         throw new IllegalArgumentException JavaDoc ("font format not recognized");
730     }
731     final InputStream fStream = fontStream;
732     Object JavaDoc ret = java.security.AccessController.doPrivileged(
733        new java.security.PrivilegedAction JavaDoc() {
734           public Object JavaDoc run() {
735           File tFile = null;
736           try {
737               tFile = File.createTempFile("+~JF", ".tmp", null);
738               tFile.deleteOnExit();
739               BufferedInputStream inStream =
740               new BufferedInputStream(fStream);
741               FileOutputStream outStream = new FileOutputStream(tFile);
742               int bytesRead = 0;
743               int bufSize = 8192;
744               byte [] buf = new byte[bufSize];
745               while (bytesRead != -1) {
746               bytesRead = inStream.read(buf, 0, bufSize);
747               if (bytesRead != -1) {
748                   outStream.write(buf, 0, bytesRead);
749               }
750               }
751               /* don't close the input stream */
752               outStream.close();
753           } catch (IOException e) {
754               return e;
755           }
756           return tFile;
757           }
758       });
759
760     if (ret instanceof File) {
761         return new Font JavaDoc((File)ret, fontFormat, true);
762     } else if (ret instanceof IOException) {
763         throw (IOException)ret;
764     } else {
765         throw new FontFormatException JavaDoc("Couldn't access font stream");
766     }
767     }
768
769     /**
770      * Returns a new <code>Font</code> using the specified font type
771      * and the specified font file. The new <code>Font</code> is
772      * created with a point size of 1 and style {@link #PLAIN PLAIN}.
773      * This base font can then be used with the <code>deriveFont</code>
774      * methods in this class to derive new <code>Font</code> objects with
775      * varying sizes, styles, transforms and font features.
776      * @param fontFormat the type of the <code>Font</code>, which is
777      * {@link #TRUETYPE_FONT TRUETYPE_FONT} if a TrueType resource is
778      * specified or {@link #TYPE1_FONT TYPE1_FONT} if a Type 1 resource is
779      * specified.
780      * So long as the returned font, or its derived fonts are referenced
781      * the implementation may continue to access <code>fontFile</code>
782      * to retrieve font data. Thus the results are undefined if the file
783      * is changed, or becomes inaccessible.
784      * @param fontFile a <code>File</code> object representing the
785      * input data for the font.
786      * @return a new <code>Font</code> created with the specified font type.
787      * @throws IllegalArgumentException if <code>fontFormat</code> is not
788      * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
789      * @throws NullPointerException if <code>fontFile</code> is null.
790      * @throws IOException if the <code>fontFile</code> cannot be read.
791      * @throws FontFormatException if <code>fontFile</code> does
792      * not contain the required font tables for the specified format.
793      * @throws SecurityException if the executing code does not have
794      * permission to read from the file.
795      * @since 1.5
796      */

797     public static Font JavaDoc createFont(int fontFormat, File fontFile)
798     throws java.awt.FontFormatException JavaDoc, java.io.IOException JavaDoc {
799     if (fontFormat != Font.TRUETYPE_FONT &&
800         fontFormat != Font.TYPE1_FONT) {
801         throw new IllegalArgumentException JavaDoc ("font format not recognized");
802     }
803     SecurityManager JavaDoc sm = System.getSecurityManager();
804     if (sm != null) {
805         FilePermission filePermission =
806             new FilePermission(fontFile.getPath(), "read");
807         sm.checkPermission(filePermission);
808     }
809     if (!fontFile.canRead()) {
810         throw new IOException("Can't read " + fontFile);
811     }
812     return new Font JavaDoc(fontFile, fontFormat, false);
813     }
814
815     /**
816      * Returns a copy of the transform associated with this
817      * <code>Font</code>.
818      * @return an {@link AffineTransform} object representing the
819      * transform attribute of this <code>Font</code> object.
820      */

821     public AffineTransform JavaDoc getTransform() {
822     /* The most common case is the identity transform. Most callers
823      * should call isTransformed() first, to decide if they need to
824      * get the transform, but some may not. Here we check to see
825      * if we have a nonidentity transform, and only do the work to
826      * fetch and/or compute it if so, otherwise we return a new
827      * identity transform.
828      *
829      * Note that the transform is _not_ necessarily the same as
830      * the transform passed in as an Attribute in a Map, as the
831      * transform returned will also reflect the effects of WIDTH and
832      * SUPERSCRIPT attributes. Clients who want the actual transform
833      * need to call getRequestedAttributes.
834      */

835     if (nonIdentityTx) {
836             AffineTransform JavaDoc at = null;
837         Object JavaDoc obj = getRequestedAttributes().get(TextAttribute.TRANSFORM);
838         if (obj != null) {
839         if( obj instanceof TransformAttribute JavaDoc ){
840             at = ((TransformAttribute JavaDoc)obj).getTransform();
841         }
842         else {
843             if ( obj instanceof AffineTransform JavaDoc){
844             at = new AffineTransform JavaDoc((AffineTransform JavaDoc)obj);
845             }
846         }
847         } else {
848                 at = new AffineTransform JavaDoc();
849             }
850             
851             if (superscript != 0) {
852                 // can't get ascent and descent here, recursive call to this fn, so use pointsize
853
// let users combine super- and sub-scripting
854
double trans = 0;
855                 int n = 0;
856                 boolean up = superscript > 0;
857                 int sign = up ? -1 : 1;
858                 int ss = up ? superscript : -superscript;
859
860                 while ((ss & 7) > n) {
861                     int newn = ss & 7;
862                     trans += sign * (ssinfo[newn] - ssinfo[n]);
863                     ss >>= 3;
864                     sign = -sign;
865                     n = newn;
866                 }
867                 trans *= pointSize;
868                 double scale = Math.pow(2./3., n);
869
870                 at.preConcatenate(AffineTransform.getTranslateInstance(0, trans));
871                 at.scale(scale, scale);
872
873                 // note on placement and italics
874
// We preconcatenate the transform because we don't want to translate along
875
// the italic angle, but purely perpendicular to the baseline. While this
876
// looks ok for superscripts, it can lead subscripts to stack on each other
877
// and bring the following text too close. The way we deal with potential
878
// collisions that can occur in the case of italics is by adjusting the
879
// horizontal spacing of the adjacent glyphvectors. Examine the italic
880
// angle of both vectors, if one is non-zero, compute the minimum ascent
881
// and descent, and then the x position at each for each vector along its
882
// italic angle starting from its (offset) baseline. Compute the difference
883
// between the x positions and use the maximum difference to adjust the
884
// position of the right gv.
885
}
886
887             if (width != 1f) {
888                 at.scale(width, 1f);
889             }
890
891             return at;
892         }
893
894         return new AffineTransform JavaDoc();
895     }
896
897     // x = r^0 + r^1 + r^2... r^n
898
// rx = r^1 + r^2 + r^3... r^(n+1)
899
// x - rx = r^0 - r^(n+1)
900
// x (1 - r) = r^0 - r^(n+1)
901
// x = (r^0 - r^(n+1)) / (1 - r)
902
// x = (1 - r^(n+1)) / (1 - r)
903

904     // scale ratio is 2/3
905
// trans = 1/2 of ascent * x
906
// assume ascent is 3/4 of point size
907

908     private static final float[] ssinfo = {
909         0.0f,
910         0.375f,
911         0.625f,
912         0.7916667f,
913         0.9027778f,
914         0.9768519f,
915         1.0262346f,
916         1.0591564f,
917     };
918
919     /**
920      * Returns the family name of this <code>Font</code>.
921      *
922      * <p>The family name of a font is font specific. Two fonts such as
923      * Helvetica Italic and Helvetica Bold have the same family name,
924      * <i>Helvetica</i>, whereas their font face names are
925      * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of
926      * available family names may be obtained by using the
927      * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
928      *
929      * <p>Use <code>getName</code> to get the logical name of the font.
930      * Use <code>getFontName</code> to get the font face name of the font.
931      * @return a <code>String</code> that is the family name of this
932      * <code>Font</code>.
933      *
934      * @see #getName
935      * @see #getFontName
936      * @since JDK1.1
937      */

938     public String JavaDoc getFamily() {
939     return getFamily_NoClientCode();
940     }
941     // NOTE: This method is called by privileged threads.
942
// We implement this functionality in a package-private
943
// method to insure that it cannot be overridden by client
944
// subclasses.
945
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
946
final String JavaDoc getFamily_NoClientCode() {
947       return getFamily(Locale.getDefault());
948     }
949
950     /**
951      * Returns the family name of this <code>Font</code>, localized for
952      * the specified locale.
953      *
954      * <p>The family name of a font is font specific. Two fonts such as
955      * Helvetica Italic and Helvetica Bold have the same family name,
956      * <i>Helvetica</i>, whereas their font face names are
957      * <i>Helvetica Bold</i> and <i>Helvetica Italic</i>. The list of
958      * available family names may be obtained by using the
959      * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
960      *
961      * <p>Use <code>getFontName</code> to get the font face name of the font.
962      * @param l locale for which to get the family name
963      * @return a <code>String</code> representing the family name of the
964      * font, localized for the specified locale.
965      * @see #getFontName
966      * @see java.util.Locale
967      * @since 1.2
968      */

969     public String JavaDoc getFamily(Locale JavaDoc l) {
970         if (l == null) {
971             throw new NullPointerException JavaDoc("null locale doesn't mean default");
972         }
973     return getFont2D().getFamilyName(l);
974     }
975
976     /**
977      * Returns the postscript name of this <code>Font</code>.
978      * Use <code>getFamily</code> to get the family name of the font.
979      * Use <code>getFontName</code> to get the font face name of the font.
980      * @return a <code>String</code> representing the postscript name of
981      * this <code>Font</code>.
982      * @since 1.2
983      */

984     public String JavaDoc getPSName() {
985     return getFont2D().getPostscriptName();
986     }
987
988     /**
989      * Returns the logical name of this <code>Font</code>.
990      * Use <code>getFamily</code> to get the family name of the font.
991      * Use <code>getFontName</code> to get the font face name of the font.
992      * @return a <code>String</code> representing the logical name of
993      * this <code>Font</code>.
994      * @see #getFamily
995      * @see #getFontName
996      * @since JDK1.0
997      */

998     public String JavaDoc getName() {
999     return name;
1000    }
1001
1002    /**
1003     * Returns the font face name of this <code>Font</code>. For example,
1004     * Helvetica Bold could be returned as a font face name.
1005     * Use <code>getFamily</code> to get the family name of the font.
1006     * Use <code>getName</code> to get the logical name of the font.
1007     * @return a <code>String</code> representing the font face name of
1008     * this <code>Font</code>.
1009     * @see #getFamily
1010     * @see #getName
1011     * @since 1.2
1012     */

1013    public String JavaDoc getFontName() {
1014      return getFontName(Locale.getDefault());
1015    }
1016
1017    /**
1018     * Returns the font face name of the <code>Font</code>, localized
1019     * for the specified locale. For example, Helvetica Fett could be
1020     * returned as the font face name.
1021     * Use <code>getFamily</code> to get the family name of the font.
1022     * @param l a locale for which to get the font face name
1023     * @return a <code>String</code> representing the font face name,
1024     * localized for the specified locale.
1025     * @see #getFamily
1026     * @see java.util.Locale
1027     */

1028    public String JavaDoc getFontName(Locale JavaDoc l) {
1029        if (l == null) {
1030            throw new NullPointerException JavaDoc("null locale doesn't mean default");
1031        }
1032    return getFont2D().getFontName(l);
1033    }
1034
1035    /**
1036     * Returns the style of this <code>Font</code>. The style can be
1037     * PLAIN, BOLD, ITALIC, or BOLD+ITALIC.
1038     * @return the style of this <code>Font</code>
1039     * @see #isPlain
1040     * @see #isBold
1041     * @see #isItalic
1042     * @since JDK1.0
1043     */

1044    public int getStyle() {
1045    return style;
1046    }
1047
1048    /**
1049     * Returns the point size of this <code>Font</code>, rounded to
1050     * an integer.
1051     * Most users are familiar with the idea of using <i>point size</i> to
1052     * specify the size of glyphs in a font. This point size defines a
1053     * measurement between the baseline of one line to the baseline of the
1054     * following line in a single spaced text document. The point size is
1055     * based on <i>typographic points</i>, approximately 1/72 of an inch.
1056     * <p>
1057     * The Java(tm)2D API adopts the convention that one point is
1058     * equivalent to one unit in user coordinates. When using a
1059     * normalized transform for converting user space coordinates to
1060     * device space coordinates 72 user
1061     * space units equal 1 inch in device space. In this case one point
1062     * is 1/72 of an inch.
1063     * @return the point size of this <code>Font</code> in 1/72 of an
1064     * inch units.
1065     * @see #getSize2D
1066     * @see GraphicsConfiguration#getDefaultTransform
1067     * @see GraphicsConfiguration#getNormalizingTransform
1068     * @since JDK1.0
1069     */

1070    public int getSize() {
1071    return size;
1072    }
1073
1074    /**
1075     * Returns the point size of this <code>Font</code> in
1076     * <code>float</code> value.
1077     * @return the point size of this <code>Font</code> as a
1078     * <code>float</code> value.
1079     * @see #getSize
1080     * @since 1.2
1081     */

1082    public float getSize2D() {
1083    return pointSize;
1084    }
1085
1086    /**
1087     * Indicates whether or not this <code>Font</code> object's style is
1088     * PLAIN.
1089     * @return <code>true</code> if this <code>Font</code> has a
1090     * PLAIN sytle;
1091     * <code>false</code> otherwise.
1092     * @see java.awt.Font#getStyle
1093     * @since JDK1.0
1094     */

1095    public boolean isPlain() {
1096    return style == 0;
1097    }
1098
1099    /**
1100     * Indicates whether or not this <code>Font</code> object's style is
1101     * BOLD.
1102     * @return <code>true</code> if this <code>Font</code> object's
1103     * style is BOLD;
1104     * <code>false</code> otherwise.
1105     * @see java.awt.Font#getStyle
1106     * @since JDK1.0
1107     */

1108    public boolean isBold() {
1109    return (style & BOLD) != 0;
1110    }
1111
1112    /**
1113     * Indicates whether or not this <code>Font</code> object's style is
1114     * ITALIC.
1115     * @return <code>true</code> if this <code>Font</code> object's
1116     * style is ITALIC;
1117     * <code>false</code> otherwise.
1118     * @see java.awt.Font#getStyle
1119     * @since JDK1.0
1120     */

1121    public boolean isItalic() {
1122    return (style & ITALIC) != 0;
1123    }
1124
1125    /**
1126     * Indicates whether or not this <code>Font</code> object has a
1127     * transform that affects its size in addition to the Size
1128     * attribute.
1129     * @return <code>true</code> if this <code>Font</code> object
1130     * has a non-identity AffineTransform attribute.
1131     * <code>false</code> otherwise.
1132     * @see java.awt.Font#getTransform
1133     * @since 1.4
1134     */

1135    public boolean isTransformed() {
1136    return nonIdentityTx;
1137    }
1138
1139    /**
1140     * Returns a <code>Font</code> object from the system properties list.
1141     * <code>nm</code> is treated as the name of a system property to be
1142     * obtained. The <code>String</code> value of this property is then
1143     * interpreted as a <code>Font</code> object according to the
1144     * specification of <code>Font.decode(String)</code>
1145     * If the specified property is not found, null is returned instead.
1146     *
1147     * @param nm the property name
1148     * @return a <code>Font</code> object that the property name
1149     * describes, or null if no such property exists.
1150     * @throws NullPointerException if nm is null.
1151     * @since 1.2
1152     * @see #decode(String)
1153     */

1154    public static Font JavaDoc getFont(String JavaDoc nm) {
1155    return getFont(nm, null);
1156    }
1157
1158    /**
1159     * Returns the <code>Font</code> that the <code>str</code>
1160     * argument describes.
1161     * To ensure that this method returns the desired Font,
1162     * format the <code>str</code> parameter in
1163     * one of these ways
1164     * <p>
1165     * <ul>
1166     * <li><em>fontname-style-pointsize</em>
1167     * <li><em>fontname-pointsize</em>
1168     * <li><em>fontname-style</em>
1169     * <li><em>fontname</em>
1170     * <li><em>fontname style pointsize</em>
1171     * <li><em>fontname pointsize</em>
1172     * <li><em>fontname style</em>
1173     * <li><em>fontname</em>
1174     * </ul>
1175     * in which <i>style</i> is one of the four
1176     * case-insensitive strings:
1177     * <code>"PLAIN"</code>, <code>"BOLD"</code>, <code>"BOLDITALIC"</code>, or
1178     * <code>"ITALIC"</code>, and pointsize is a positive decimal integer
1179     * representation of the point size.
1180     * For example, if you want a font that is Arial, bold, with
1181     * a point size of 18, you would call this method with:
1182     * "Arial-BOLD-18".
1183     * This is equivalent to calling the Font constructor :
1184     * <code>new Font("Arial", Font.BOLD, 18);</code>
1185     * and the values are interpreted as specified by that constructor.
1186     * <p>
1187     * A valid trailing decimal field is always interpreted as the pointsize.
1188     * Therefore a fontname containing a trailing decimal value should not
1189     * be used in the fontname only form.
1190     * <p>
1191     * If a style name field is not one of the valid style strings, it is
1192     * interpreted as part of the font name, and the default style is used.
1193     * <p>
1194     * Only one of ' ' or '-' may be used to separate fields in the input.
1195     * The identified separator is the one closest to the end of the string
1196     * which separates a valid pointsize, or a valid style name from
1197     * the rest of the string.
1198     * Null (empty) pointsize and style fields are treated
1199     * as valid fields with the default value for that field.
1200     *<p>
1201     * Some font names may include the separator characters ' ' or '-'.
1202     * If <code>str</code> is not formed with 3 components, e.g. such that
1203     * <code>style</code> or <code>pointsize</code> fields are not present in
1204     * <code>str</code>, and <code>fontname</code> also contains a
1205     * character determined to be the separator character
1206     * then these characters where they appear as intended to be part of
1207     * <code>fontname</code> may instead be interpreted as separators
1208     * so the font name may not be properly recognised.
1209     *
1210     * <p>
1211     * The default size is 12 and the default style is PLAIN.
1212     * If <code>str</code> does not specify a valid size, the returned
1213     * <code>Font</code> has a size of 12. If <code>str</code> does not
1214     * specify a valid style, the returned Font has a style of PLAIN.
1215     * If you do not specify a valid font name in
1216     * the <code>str</code> argument, this method will return
1217     * a font with the family name "Dialog".
1218     * To determine what font family names are available on
1219     * your system, use the
1220     * {@link GraphicsEnvironment#getAvailableFontFamilyNames()} method.
1221     * If <code>str</code> is <code>null</code>, a new <code>Font</code>
1222     * is returned with the family name "Dialog", a size of 12 and a
1223     * PLAIN style.
1224     * @param str the name of the font, or <code>null</code>
1225     * @return the <code>Font</code> object that <code>str</code>
1226     * describes, or a new default <code>Font</code> if
1227     * <code>str</code> is <code>null</code>.
1228     * @see #getFamily
1229     * @since JDK1.1
1230     */

1231    public static Font JavaDoc decode(String JavaDoc str) {
1232    String JavaDoc fontName = str;
1233    String JavaDoc styleName = "";
1234    int fontSize = 12;
1235    int fontStyle = Font.PLAIN;
1236
1237        if (str == null) {
1238            return new Font JavaDoc("Dialog", fontStyle, fontSize);
1239        }
1240    
1241    int lastHyphen = str.lastIndexOf('-');
1242    int lastSpace = str.lastIndexOf(' ');
1243    char sepChar = (lastHyphen > lastSpace) ? '-' : ' ';
1244    int sizeIndex = str.lastIndexOf(sepChar);
1245    int styleIndex = str.lastIndexOf(sepChar, sizeIndex-1);
1246    int strlen = str.length();
1247
1248    if (sizeIndex > 0 && sizeIndex+1 < strlen) {
1249        try {
1250        fontSize =
1251            Integer.valueOf(str.substring(sizeIndex+1)).intValue();
1252        if (fontSize <= 0) {
1253            fontSize = 12;
1254        }
1255        } catch (NumberFormatException JavaDoc e) {
1256        /* It wasn't a valid size, if we didn't also find the
1257         * start of the style string perhaps this is the style */

1258        styleIndex = sizeIndex;
1259        sizeIndex = strlen;
1260        if (str.charAt(sizeIndex-1) == sepChar) {
1261            sizeIndex--;
1262        }
1263        }
1264    }
1265
1266    if (styleIndex >= 0 && styleIndex+1 < strlen) {
1267        styleName = str.substring(styleIndex+1, sizeIndex);
1268        styleName = styleName.toLowerCase(Locale.ENGLISH);
1269        if (styleName.equals("bolditalic")) {
1270        fontStyle = Font.BOLD | Font.ITALIC;
1271        } else if (styleName.equals("italic")) {
1272        fontStyle = Font.ITALIC;
1273        } else if (styleName.equals("bold")) {
1274        fontStyle = Font.BOLD;
1275        } else if (styleName.equals("plain")) {
1276        fontStyle = Font.PLAIN;
1277        } else {
1278        /* this string isn't any of the expected styles, so
1279         * assume its part of the font name
1280         */

1281        styleIndex = sizeIndex;
1282        if (str.charAt(styleIndex-1) == sepChar) {
1283            styleIndex--;
1284        }
1285        }
1286        fontName = str.substring(0, styleIndex);
1287
1288    } else {
1289        int fontEnd = strlen;
1290        if (styleIndex > 0) {
1291        fontEnd = styleIndex;
1292        } else if (sizeIndex > 0) {
1293        fontEnd = sizeIndex;
1294        }
1295        if (fontEnd > 0 && str.charAt(fontEnd-1) == sepChar) {
1296        fontEnd--;
1297        }
1298        fontName = str.substring(0, fontEnd);
1299    }
1300
1301    return new Font JavaDoc(fontName, fontStyle, fontSize);
1302    }
1303
1304    /**
1305     * Gets the specified <code>Font</code> from the system properties
1306     * list. As in the <code>getProperty</code> method of
1307     * <code>System</code>, the first
1308     * argument is treated as the name of a system property to be
1309     * obtained. The <code>String</code> value of this property is then
1310     * interpreted as a <code>Font</code> object.
1311     * <p>
1312     * The property value should be one of the forms accepted by
1313     * <code>Font.decode(String)</code>
1314     * If the specified property is not found, the <code>font</code>
1315     * argument is returned instead.
1316     * @param nm the case-insensitive property name
1317     * @param font a default <code>Font</code> to return if property
1318     * <code>nm</code> is not defined
1319     * @return the <code>Font</code> value of the property.
1320     * @throws NullPointerException if nm is null.
1321     * @see #decode(String)
1322     */

1323    public static Font JavaDoc getFont(String JavaDoc nm, Font JavaDoc font) {
1324    String JavaDoc str = null;
1325    try {
1326        str =System.getProperty(nm);
1327    } catch(SecurityException JavaDoc e) {
1328    }
1329    if (str == null) {
1330        return font;
1331    }
1332    return decode ( str );
1333    }
1334
1335
1336    /**
1337     * Returns a hashcode for this <code>Font</code>.
1338     * @return a hashcode value for this <code>Font</code>.
1339     * @since JDK1.0
1340     */

1341    public int hashCode() {
1342    return name.hashCode() ^ style ^ size;
1343    }
1344
1345    /**
1346     * Compares this <code>Font</code> object to the specified
1347     * <code>Object</code>.
1348     * @param obj the <code>Object</code> to compare
1349     * @return <code>true</code> if the objects are the same
1350     * or if the argument is a <code>Font</code> object
1351     * describing the same font as this object;
1352     * <code>false</code> otherwise.
1353     * @since JDK1.0
1354     */

1355    public boolean equals(Object JavaDoc obj) {
1356        if (obj == this) {
1357        return true;
1358        }
1359
1360    if (obj != null) {
1361      try {
1362        Font JavaDoc font = (Font JavaDoc)obj;
1363        if ((size == font.size) &&
1364        (pointSize == font.pointSize) &&
1365        (style == font.style) &&
1366                (superscript == font.superscript) &&
1367                (width == font.width) &&
1368        name.equals(font.name)) {
1369        
1370        double[] thismat = this.getMatrix();
1371        double[] thatmat = font.getMatrix();
1372        
1373        return thismat[0] == thatmat[0]
1374            && thismat[1] == thatmat[1]
1375            && thismat[2] == thatmat[2]
1376            && thismat[3] == thatmat[3]
1377            && thismat[4] == thatmat[4]
1378            && thismat[5] == thatmat[5];
1379        }
1380      }
1381      catch (ClassCastException JavaDoc e) {
1382      }
1383    }
1384    return false;
1385    }
1386
1387    /**
1388     * Converts this <code>Font</code> object to a <code>String</code>
1389     * representation.
1390     * @return a <code>String</code> representation of this
1391     * <code>Font</code> object.
1392     * @since JDK1.0
1393     */

1394    // NOTE: This method may be called by privileged threads.
1395
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
1396
public String JavaDoc toString() {
1397    String JavaDoc strStyle;
1398
1399    if (isBold()) {
1400        strStyle = isItalic() ? "bolditalic" : "bold";
1401    } else {
1402        strStyle = isItalic() ? "italic" : "plain";
1403    }
1404
1405    return getClass().getName() + "[family=" + getFamily() + ",name=" + name + ",style=" +
1406        strStyle + ",size=" + size + "]";
1407    } // toString()
1408

1409
1410    /** Serialization support. A <code>readObject</code>
1411     * method is neccessary because the constructor creates
1412     * the font's peer, and we can't serialize the peer.
1413     * Similarly the computed font "family" may be different
1414     * at <code>readObject</code> time than at
1415     * <code>writeObject</code> time. An integer version is
1416     * written so that future versions of this class will be
1417     * able to recognize serialized output from this one.
1418     */

1419    /**
1420     * The <code>Font</code> Serializable Data Form.
1421     *
1422     * @serial
1423     */

1424    private int fontSerializedDataVersion = 1;
1425
1426    /**
1427     * Writes default serializable fields to a stream.
1428     *
1429     * @param s the <code>ObjectOutputStream</code> to write
1430     * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
1431     * @see #readObject(java.io.ObjectInputStream)
1432     */

1433    private void writeObject(java.io.ObjectOutputStream JavaDoc s)
1434      throws java.lang.ClassNotFoundException JavaDoc,
1435         java.io.IOException JavaDoc
1436    {
1437      s.defaultWriteObject();
1438    }
1439
1440    /**
1441     * Reads the <code>ObjectInputStream</code>.
1442     * Unrecognized keys or values will be ignored.
1443     *
1444     * @param s the <code>ObjectInputStream</code> to read
1445     * @serial
1446     * @see #writeObject(java.io.ObjectOutputStream)
1447     */

1448    private void readObject(java.io.ObjectInputStream JavaDoc s)
1449      throws java.lang.ClassNotFoundException JavaDoc,
1450         java.io.IOException JavaDoc
1451    {
1452      s.defaultReadObject();
1453      if (pointSize == 0) {
1454        pointSize = (float)size;
1455      }
1456      width = 1f; // init transient field
1457
initializeFont(fRequestedAttributes);
1458    }
1459
1460    /**
1461     * Returns the number of glyphs in this <code>Font</code>. Glyph codes
1462     * for this <code>Font</code> range from 0 to
1463     * <code>getNumGlyphs()</code> - 1.
1464     * @return the number of glyphs in this <code>Font</code>.
1465     * @since 1.2
1466     */

1467    public int getNumGlyphs() {
1468    return getFont2D().getNumGlyphs();
1469    }
1470
1471    /**
1472     * Returns the glyphCode which is used when this <code>Font</code>
1473     * does not have a glyph for a specified unicode.
1474     * @return the glyphCode of this <code>Font</code>.
1475     * @since 1.2
1476     */

1477    public int getMissingGlyphCode() {
1478    return getFont2D().getMissingGlyphCode();
1479    }
1480
1481    /**
1482     * get the transform matrix for this font.
1483     */

1484    /* for identity transforms this code attempts to share a matrix
1485     * amongst fonts with the same pt size */

1486    private static double cachedMat[];
1487    private double[] getMatrix() {
1488        if (matrix == null) {
1489        double ptSize = this.getSize2D();
1490        if (nonIdentityTx) {
1491        AffineTransform JavaDoc tx = getTransform();
1492        tx.scale(ptSize, ptSize);
1493        tx.getMatrix(matrix = new double[6]);
1494        } else {
1495        synchronized (Font JavaDoc.class) {
1496            double[] m = cachedMat;
1497            if (m == null || m[0] != ptSize) {
1498            cachedMat = m =
1499                new double[] {ptSize, 0, 0, ptSize, 0, 0 };
1500            }
1501            matrix = m;
1502        }
1503        }
1504        }
1505    return matrix;
1506    }
1507
1508    /**
1509     * Returns the baseline appropriate for displaying this character.
1510     * <p>
1511     * Large fonts can support different writing systems, and each system can
1512     * use a different baseline.
1513     * The character argument determines the writing system to use. Clients
1514     * should not assume all characters use the same baseline.
1515     *
1516     * @param c a character used to identify the writing system
1517     * @return the baseline appropriate for the specified character.
1518     * @see LineMetrics#getBaselineOffsets
1519     * @see #ROMAN_BASELINE
1520     * @see #CENTER_BASELINE
1521     * @see #HANGING_BASELINE
1522     * @since 1.2
1523     */

1524    public byte getBaselineFor(char c) {
1525    return getFont2D().getBaselineFor(c);
1526    }
1527
1528    /**
1529     * Returns a map of font attributes available in this
1530     * <code>Font</code>. Attributes include things like ligatures and
1531     * glyph substitution.
1532     * @return the attributes map of this <code>Font</code>.
1533     */

1534    public Map JavaDoc<TextAttribute JavaDoc,?> getAttributes(){
1535        return (Map JavaDoc<TextAttribute JavaDoc,?>)getRequestedAttributes().clone();
1536    }
1537
1538    /**
1539     * Returns the keys of all the attributes supported by this
1540     * <code>Font</code>. These attributes can be used to derive other
1541     * fonts.
1542     * @return an array containing the keys of all the attributes
1543     * supported by this <code>Font</code>.
1544     * @since 1.2
1545     */

1546    public Attribute JavaDoc[] getAvailableAttributes(){
1547        Attribute JavaDoc attributes[] = {
1548            TextAttribute.FAMILY,
1549            TextAttribute.WEIGHT,
1550            TextAttribute.POSTURE,
1551            TextAttribute.SIZE,
1552        TextAttribute.TRANSFORM,
1553            TextAttribute.SUPERSCRIPT,
1554            TextAttribute.WIDTH,
1555        };
1556
1557        return attributes;
1558    }
1559
1560    /**
1561     * Creates a new <code>Font</code> object by replicating this
1562     * <code>Font</code> object and applying a new style and size.
1563     * @param style the style for the new <code>Font</code>
1564     * @param size the size for the new <code>Font</code>
1565     * @return a new <code>Font</code> object.
1566     * @since 1.2
1567     */

1568    public Font JavaDoc deriveFont(int style, float size){
1569    Hashtable JavaDoc newAttributes = (Hashtable JavaDoc)getRequestedAttributes().clone();
1570    applyStyle(style, newAttributes);
1571    applySize(size, newAttributes);
1572        return new Font JavaDoc(newAttributes, createdFont, font2DHandle);
1573    }
1574
1575    /**
1576     * Creates a new <code>Font</code> object by replicating this
1577     * <code>Font</code> object and applying a new style and transform.
1578     * @param style the style for the new <code>Font</code>
1579     * @param trans the <code>AffineTransform</code> associated with the
1580     * new <code>Font</code>
1581     * @return a new <code>Font</code> object.
1582     * @throws IllegalArgumentException if <code>trans</code> is
1583     * <code>null</code>
1584     * @since 1.2
1585     */

1586    public Font JavaDoc deriveFont(int style, AffineTransform JavaDoc trans){
1587    Hashtable JavaDoc newAttributes = (Hashtable JavaDoc)getRequestedAttributes().clone();
1588    applyStyle(style, newAttributes);
1589    applyTransform(trans, newAttributes);
1590        return new Font JavaDoc(newAttributes, createdFont, font2DHandle);
1591    }
1592
1593    /**
1594     * Creates a new <code>Font</code> object by replicating the current
1595     * <code>Font</code> object and applying a new size to it.
1596     * @param size the size for the new <code>Font</code>.
1597     * @return a new <code>Font</code> object.
1598     * @since 1.2
1599     */

1600    public Font JavaDoc deriveFont(float size){
1601    Hashtable JavaDoc newAttributes = (Hashtable JavaDoc)getRequestedAttributes().clone();
1602    applySize(size, newAttributes);
1603        return new Font JavaDoc(newAttributes, createdFont, font2DHandle);
1604    }
1605
1606    /**
1607     * Creates a new <code>Font</code> object by replicating the current
1608     * <code>Font</code> object and applying a new transform to it.
1609     * @param trans the <code>AffineTransform</code> associated with the
1610     * new <code>Font</code>
1611     * @return a new <code>Font</code> object.
1612     * @throws IllegalArgumentException if <code>trans</code> is
1613     * <code>null</code>
1614     * @since 1.2
1615     */

1616    public Font JavaDoc deriveFont(AffineTransform JavaDoc trans){
1617    Hashtable JavaDoc newAttributes = (Hashtable JavaDoc)getRequestedAttributes().clone();
1618    applyTransform(trans, newAttributes);
1619        return new Font JavaDoc(newAttributes, createdFont, font2DHandle);
1620    }
1621
1622    /**
1623     * Creates a new <code>Font</code> object by replicating the current
1624     * <code>Font</code> object and applying a new style to it.
1625     * @param style the style for the new <code>Font</code>
1626     * @return a new <code>Font</code> object.
1627     * @since 1.2
1628     */

1629    public Font JavaDoc deriveFont(int style){
1630    Hashtable JavaDoc newAttributes = (Hashtable JavaDoc)getRequestedAttributes().clone();
1631    applyStyle(style, newAttributes);
1632        return new Font JavaDoc(newAttributes, createdFont, font2DHandle);
1633    }
1634
1635    /**
1636     * Creates a new <code>Font</code> object by replicating the current
1637     * <code>Font</code> object and applying a new set of font attributes
1638     * to it.
1639     * @param attributes a map of attributes enabled for the new
1640     * <code>Font</code>
1641     * @return a new <code>Font</code> object.
1642     * @since 1.2
1643     */

1644    public Font JavaDoc deriveFont(Map JavaDoc<? extends Attribute JavaDoc, ?> attributes) {
1645    if (attributes == null || attributes.size() == 0) {
1646        return this;
1647    }
1648
1649        Hashtable JavaDoc newAttrs = new Hashtable JavaDoc(getAttributes());
1650    Attribute JavaDoc validAttribs[] = getAvailableAttributes();
1651    Object JavaDoc obj;
1652
1653    for(int i = 0; i < validAttribs.length; i++){
1654      if ((obj = attributes.get(validAttribs[i])) != null) {
1655        newAttrs.put(validAttribs[i],obj);
1656      }
1657    }
1658        return new Font JavaDoc(newAttrs, createdFont, font2DHandle);
1659    }
1660
1661    /**
1662     * Checks if this <code>Font</code> has a glyph for the specified
1663     * character.
1664     *
1665     * <p> <b>Note:</b> This method cannot handle <a
1666     * HREF="../../java/lang/Character.html#supplementary"> supplementary
1667     * characters</a>. To support all Unicode characters, including
1668     * supplementary characters, use the {@link #canDisplay(int)}
1669     * method or <code>canDisplayUpTo</code> methods.
1670     *
1671     * @param c the character for which a glyph is needed
1672     * @return <code>true</code> if this <code>Font</code> has a glyph for this
1673     * character; <code>false</code> otherwise.
1674     * @since 1.2
1675     */

1676    public boolean canDisplay(char c){
1677    return getFont2D().canDisplay(c);
1678    }
1679
1680    /**
1681     * Checks if this <code>Font</code> has a glyph for the specified
1682     * character.
1683     *
1684     * @param codePoint the character (Unicode code point) for which a glyph
1685     * is needed.
1686     * @return <code>true</code> if this <code>Font</code> has a glyph for the
1687     * character; <code>false</code> otherwise.
1688     * @throws IllegalArgumentException if the code point is not a valid Unicode
1689     * code point.
1690     * @see Character#isValidCodePoint(int)
1691     * @since 1.5
1692     */

1693    public boolean canDisplay(int codePoint) {
1694    if (!Character.isValidCodePoint(codePoint)) {
1695        throw new IllegalArgumentException JavaDoc("invalid code point: " + Integer.toHexString(codePoint));
1696    }
1697    return getFont2D().canDisplay(codePoint);
1698    }
1699
1700    /**
1701     * Indicates whether or not this <code>Font</code> can display a
1702     * specified <code>String</code>. For strings with Unicode encoding,
1703     * it is important to know if a particular font can display the
1704     * string. This method returns an offset into the <code>String</code>
1705     * <code>str</code> which is the first character this
1706     * <code>Font</code> cannot display without using the missing glyph
1707     * code. If the <code>Font</code> can display all characters, -1 is
1708     * returned.
1709     * @param str a <code>String</code> object
1710     * @return an offset into <code>str</code> that points
1711     * to the first character in <code>str</code> that this
1712     * <code>Font</code> cannot display; or <code>-1</code> if
1713     * this <code>Font</code> can display all characters in
1714     * <code>str</code>.
1715     * @since 1.2
1716     */

1717    public int canDisplayUpTo(String JavaDoc str) {
1718        return canDisplayUpTo(new StringCharacterIterator JavaDoc(str), 0,
1719            str.length());
1720    }
1721
1722    /**
1723     * Indicates whether or not this <code>Font</code> can display
1724     * the characters in the specified <code>text</code>
1725     * starting at <code>start</code> and ending at
1726     * <code>limit</code>. This method is a convenience overload.
1727     * @param text the specified array of <code>char</code> values
1728     * @param start the specified starting offset (in
1729     * <code>char</code>s) into the specified array of
1730     * <code>char</code> values
1731     * @param limit the specified ending offset (in
1732     * <code>char</code>s) into the specified array of
1733     * <code>char</code> values
1734     * @return an offset into <code>text</code> that points
1735     * to the first character in <code>text</code> that this
1736     * <code>Font</code> cannot display; or <code>-1</code> if
1737     * this <code>Font</code> can display all characters in
1738     * <code>text</code>.
1739     * @since 1.2
1740     */

1741    public int canDisplayUpTo(char[] text, int start, int limit) {
1742    while (start < limit && canDisplay(text[start])) {
1743        ++start;
1744    }
1745
1746    return start == limit ? -1 : start;
1747    }
1748
1749    /**
1750     * Indicates whether or not this <code>Font</code> can display the
1751     * text specified by the <code>iter</code> starting at
1752     * <code>start</code> and ending at <code>limit</code>.
1753     *
1754     * @param iter a {@link CharacterIterator} object
1755     * @param start the specified starting offset into the specified
1756     * <code>CharacterIterator</code>.
1757     * @param limit the specified ending offset into the specified
1758     * <code>CharacterIterator</code>.
1759     * @return an offset into <code>iter</code> that points
1760     * to the first character in <code>iter</code> that this
1761     * <code>Font</code> cannot display; or <code>-1</code> if
1762     * this <code>Font</code> can display all characters in
1763     * <code>iter</code>.
1764     * @since 1.2
1765     */

1766    public int canDisplayUpTo(CharacterIterator JavaDoc iter, int start, int limit) {
1767        for (char c = iter.setIndex(start);
1768             iter.getIndex() < limit && canDisplay(c);
1769             c = iter.next()) {
1770        }
1771
1772    int result = iter.getIndex();
1773    return result == limit ? -1 : result;
1774    }
1775
1776    /**
1777     * Returns the italic angle of this <code>Font</code>. The italic angle
1778     * is the inverse slope of the caret which best matches the posture of this
1779     * <code>Font</code>.
1780     * @see TextAttribute#POSTURE
1781     * @return the angle of the ITALIC style of this <code>Font</code>.
1782     */

1783    public float getItalicAngle() {
1784    AffineTransform JavaDoc at = (isTransformed()) ? getTransform() : identityTx;
1785    return getFont2D().getItalicAngle(this, at, false, false);
1786    }
1787
1788    /**
1789     * Checks whether or not this <code>Font</code> has uniform
1790     * line metrics. A logical <code>Font</code> might be a
1791     * composite font, which means that it is composed of different
1792     * physical fonts to cover different code ranges. Each of these
1793     * fonts might have different <code>LineMetrics</code>. If the
1794     * logical <code>Font</code> is a single
1795     * font then the metrics would be uniform.
1796     * @return <code>true</code> if this <code>Font</code> has
1797     * uniform line metrics; <code>false</code> otherwise.
1798     */

1799    public boolean hasUniformLineMetrics() {
1800        return false; // REMIND always safe, but prevents caller optimize
1801
}
1802
1803    private transient SoftReference JavaDoc flmref;
1804    private FontLineMetrics defaultLineMetrics(FontRenderContext JavaDoc frc) {
1805        FontLineMetrics flm = null;
1806        if (flmref == null
1807            || (flm = (FontLineMetrics)flmref.get()) == null
1808            || !flm.frc.equals(frc)) {
1809            
1810            /* The device transform in the frc is not used in obtaining line
1811             * metrics, although it probably should be: REMIND find why not?
1812             * The font transform is used but its applied in getFontMetrics, so
1813             * just pass identity here
1814             */

1815            float [] metrics = new float[4];
1816            getFont2D().getFontMetrics(this, identityTx,
1817                                       frc.isAntiAliased(),
1818                                       frc.usesFractionalMetrics(),
1819                                       metrics);
1820            float ascent = metrics[0];
1821            float descent = metrics[1];
1822            float leading = metrics[2];
1823            float ssOffset = 0;
1824            if (superscript != 0) {
1825                ssOffset = (float)getTransform().getTranslateY();
1826                ascent -= ssOffset;
1827                descent += ssOffset;
1828            }
1829            float height = ascent + descent + leading;
1830
1831            int baselineIndex = 0; // need real index, assumes roman for everything
1832
float[] baselineOffsets = { 0, (descent/2f - ascent) / 2f, -ascent }; // need real baselines eventually
1833

1834            // !!! desperately need real data here
1835
float strikethroughOffset = ssOffset -(metrics[0] / 2.5f);
1836            float strikethroughThickness = (float)(Math.log(pointSize / 4));
1837
1838            float underlineOffset = ssOffset + strikethroughThickness / 1.5f;
1839            float underlineThickness = strikethroughThickness;
1840
1841            float italicAngle = getItalicAngle();
1842
1843            CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height,
1844                                             baselineIndex, baselineOffsets,
1845                                             strikethroughOffset, strikethroughThickness,
1846                                             underlineOffset, underlineThickness,
1847                                             ssOffset, italicAngle);
1848
1849            flm = new FontLineMetrics(0, cm, frc);
1850            flmref = new SoftReference JavaDoc(flm);
1851        }
1852
1853        return (FontLineMetrics)flm.clone();
1854    }
1855
1856    /**
1857     * Returns a {@link LineMetrics} object created with the specified
1858     * <code>String</code> and {@link FontRenderContext}.
1859     * @param str the specified <code>String</code>
1860     * @param frc the specified <code>FontRenderContext</code>
1861     * @return a <code>LineMetrics</code> object created with the
1862     * specified <code>String</code> and {@link FontRenderContext}.
1863     */

1864    public LineMetrics JavaDoc getLineMetrics( String JavaDoc str, FontRenderContext JavaDoc frc) {
1865        FontLineMetrics flm = defaultLineMetrics(frc);
1866        flm.numchars = str.length();
1867        return flm;
1868    }
1869
1870    /**
1871     * Returns a <code>LineMetrics</code> object created with the
1872     * specified arguments.
1873     * @param str the specified <code>String</code>
1874     * @param beginIndex the initial offset of <code>str</code>
1875     * @param limit the end offset of <code>str</code>
1876     * @param frc the specified <code>FontRenderContext</code>
1877     * @return a <code>LineMetrics</code> object created with the
1878     * specified arguments.
1879     */

1880    public LineMetrics JavaDoc getLineMetrics( String JavaDoc str,
1881                                    int beginIndex, int limit,
1882                                    FontRenderContext JavaDoc frc) {
1883        FontLineMetrics flm = defaultLineMetrics(frc);
1884        int numChars = limit - beginIndex;
1885        flm.numchars = (numChars < 0)? 0: numChars;
1886        return flm;
1887    }
1888
1889    /**
1890     * Returns a <code>LineMetrics</code> object created with the
1891     * specified arguments.
1892     * @param chars an array of characters
1893     * @param beginIndex the initial offset of <code>chars</code>
1894     * @param limit the end offset of <code>chars</code>
1895     * @param frc the specified <code>FontRenderContext</code>
1896     * @return a <code>LineMetrics</code> object created with the
1897     * specified arguments.
1898     */

1899    public LineMetrics JavaDoc getLineMetrics(char [] chars,
1900                                    int beginIndex, int limit,
1901                                    FontRenderContext JavaDoc frc) {
1902        FontLineMetrics flm = defaultLineMetrics(frc);
1903        int numChars = limit - beginIndex;
1904        flm.numchars = (numChars < 0)? 0: numChars;
1905        return flm;
1906    }
1907
1908    /**
1909     * Returns a <code>LineMetrics</code> object created with the
1910     * specified arguments.
1911     * @param ci the specified <code>CharacterIterator</code>
1912     * @param beginIndex the initial offset in <code>ci</code>
1913     * @param limit the end offset of <code>ci</code>
1914     * @param frc the specified <code>FontRenderContext</code>
1915     * @return a <code>LineMetrics</code> object created with the
1916     * specified arguments.
1917     */

1918    public LineMetrics JavaDoc getLineMetrics(CharacterIterator JavaDoc ci,
1919                                    int beginIndex, int limit,
1920                                    FontRenderContext JavaDoc frc) {
1921        FontLineMetrics flm = defaultLineMetrics(frc);
1922        int numChars = limit - beginIndex;
1923        flm.numchars = (numChars < 0)? 0: numChars;
1924        return flm;
1925    }
1926
1927    /**
1928     * Returns the logical bounds of the specified <code>String</code> in
1929     * the specified <code>FontRenderContext</code>. The logical bounds
1930     * contains the origin, ascent, advance, and height, which includes
1931     * the leading. The logical bounds does not always enclose all the
1932     * text. For example, in some languages and in some fonts, accent
1933     * marks can be positioned above the ascent or below the descent.
1934     * To obtain a visual bounding box, which encloses all the text,
1935     * use the {@link TextLayout#getBounds() getBounds} method of
1936     * <code>TextLayout</code>.
1937     * @param str the specified <code>String</code>
1938     * @param frc the specified <code>FontRenderContext</code>
1939     * @return a {@link Rectangle2D} that is the bounding box of the
1940     * specified <code>String</code> in the specified
1941     * <code>FontRenderContext</code>.
1942     * @see FontRenderContext
1943     * @see Font#createGlyphVector
1944     * @since 1.2
1945     */

1946    public Rectangle2D JavaDoc getStringBounds( String JavaDoc str, FontRenderContext JavaDoc frc) {
1947      char[] array = str.toCharArray();
1948      return getStringBounds(array, 0, array.length, frc);
1949    }
1950
1951   /**
1952     * Returns the logical bounds of the specified <code>String</code> in
1953     * the specified <code>FontRenderContext</code>. The logical bounds
1954     * contains the origin, ascent, advance, and height, which includes
1955     * the leading. The logical bounds does not always enclose all the
1956     * text. For example, in some languages and in some fonts, accent
1957     * marks can be positioned above the ascent or below the descent.
1958     * To obtain a visual bounding box, which encloses all the text,
1959     * use the {@link TextLayout#getBounds() getBounds} method of
1960     * <code>TextLayout</code>.
1961     * @param str the specified <code>String</code>
1962     * @param beginIndex the initial offset of <code>str</code>
1963     * @param limit the end offset of <code>str</code>
1964     * @param frc the specified <code>FontRenderContext</code>
1965     * @return a <code>Rectangle2D</code> that is the bounding box of the
1966     * specified <code>String</code> in the specified
1967     * <code>FontRenderContext</code>.
1968     * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
1969     * less than zero, or <code>limit</code> is greater than the
1970     * length of <code>str</code>, or <code>beginIndex</code>
1971     * is greater than <code>limit</code>.
1972     * @see FontRenderContext
1973     * @see Font#createGlyphVector
1974     * @since 1.2
1975     */

1976    public Rectangle2D JavaDoc getStringBounds( String JavaDoc str,
1977                                    int beginIndex, int limit,
1978                                    FontRenderContext JavaDoc frc) {
1979      String JavaDoc substr = str.substring(beginIndex, limit);
1980      return getStringBounds(substr, frc);
1981    }
1982
1983   /**
1984     * Returns the logical bounds of the specified array of characters
1985     * in the specified <code>FontRenderContext</code>. The logical
1986     * bounds contains the origin, ascent, advance, and height, which
1987     * includes the leading. The logical bounds does not always enclose
1988     * all the text. For example, in some languages and in some fonts,
1989     * accent marks can be positioned above the ascent or below the
1990     * descent. To obtain a visual bounding box, which encloses all the
1991     * text, use the {@link TextLayout#getBounds() getBounds} method of
1992     * <code>TextLayout</code>.
1993     * @param chars an array of characters
1994     * @param beginIndex the initial offset in the array of
1995     * characters
1996     * @param limit the end offset in the array of characters
1997     * @param frc the specified <code>FontRenderContext</code>
1998     * @return a <code>Rectangle2D</code> that is the bounding box of the
1999     * specified array of characters in the specified
2000     * <code>FontRenderContext</code>.
2001     * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
2002     * less than zero, or <code>limit</code> is greater than the
2003     * length of <code>chars</code>, or <code>beginIndex</code>
2004     * is greater than <code>limit</code>.
2005     * @see FontRenderContext
2006     * @see Font#createGlyphVector
2007     * @since 1.2
2008     */

2009    public Rectangle2D JavaDoc getStringBounds(char [] chars,
2010                                    int beginIndex, int limit,
2011                                    FontRenderContext JavaDoc frc) {
2012      if (beginIndex < 0) {
2013    throw new IndexOutOfBoundsException JavaDoc("beginIndex: " + beginIndex);
2014      }
2015      if (limit > chars.length) {
2016    throw new IndexOutOfBoundsException JavaDoc("limit: " + limit);
2017      }
2018      if (beginIndex > limit) {
2019    throw new IndexOutOfBoundsException JavaDoc("range length: " + (limit - beginIndex));
2020      }
2021
2022      // this code should be in textlayout
2023
// quick check for simple text, assume GV ok to use if simple
2024

2025      boolean simple = true;
2026      for (int i = beginIndex; i < limit; ++i) {
2027    char c = chars[i];
2028    if (c >= '\u0590' && c <= '\u206f') {
2029      simple = false;
2030      break;
2031    }
2032      }
2033      if (simple) {
2034    GlyphVector JavaDoc gv = new StandardGlyphVector(this, chars, beginIndex, limit - beginIndex, frc);
2035    return gv.getLogicalBounds();
2036      } else {
2037    // need char array constructor on textlayout
2038
String JavaDoc str = new String JavaDoc(chars, beginIndex, limit - beginIndex);
2039    TextLayout JavaDoc tl = new TextLayout JavaDoc(str, this, frc);
2040    return new Rectangle2D.Float JavaDoc(0, -tl.getAscent(), tl.getAdvance(), tl.getDescent() + tl.getLeading());
2041      }
2042    }
2043
2044   /**
2045     * Returns the logical bounds of the characters indexed in the
2046     * specified {@link CharacterIterator} in the
2047     * specified <code>FontRenderContext</code>. The logical bounds
2048     * contains the origin, ascent, advance, and height, which includes
2049     * the leading. The logical bounds does not always enclose all the
2050     * text. For example, in some languages and in some fonts, accent
2051     * marks can be positioned above the ascent or below the descent.
2052     * To obtain a visual bounding box, which encloses all the text,
2053     * use the {@link TextLayout#getBounds() getBounds} method of
2054     * <code>TextLayout</code>.
2055     * @param ci the specified <code>CharacterIterator</code>
2056     * @param beginIndex the initial offset in <code>ci</code>
2057     * @param limit the end offset in <code>ci</code>
2058     * @param frc the specified <code>FontRenderContext</code>
2059     * @return a <code>Rectangle2D</code> that is the bounding box of the
2060     * characters indexed in the specified <code>CharacterIterator</code>
2061     * in the specified <code>FontRenderContext</code>.
2062     * @see FontRenderContext
2063     * @see Font#createGlyphVector
2064     * @since 1.2
2065     * @throws IndexOutOfBoundsException if <code>beginIndex</code> is
2066     * less than the start index of <code>ci</code>, or
2067     * <code>limit</code> is greater than the end index of
2068     * <code>ci</code>, or <code>beginIndex</code> is greater
2069     * than <code>limit</code>
2070     */

2071    public Rectangle2D JavaDoc getStringBounds(CharacterIterator JavaDoc ci,
2072                                    int beginIndex, int limit,
2073                                    FontRenderContext JavaDoc frc) {
2074      int start = ci.getBeginIndex();
2075      int end = ci.getEndIndex();
2076
2077      if (beginIndex < start) {
2078    throw new IndexOutOfBoundsException JavaDoc("beginIndex: " + beginIndex);
2079      }
2080      if (limit > end) {
2081    throw new IndexOutOfBoundsException JavaDoc("limit: " + limit);
2082      }
2083      if (beginIndex > limit) {
2084    throw new IndexOutOfBoundsException JavaDoc("range length: " + (limit - beginIndex));
2085      }
2086
2087      char[] arr = new char[limit - beginIndex];
2088
2089      ci.setIndex(beginIndex);
2090      for(int idx = 0; idx < arr.length; idx++) {
2091    arr[idx] = ci.current();
2092    ci.next();
2093      }
2094
2095      return getStringBounds(arr,0,arr.length,frc);
2096    }
2097
2098    /**
2099     * Returns the bounds for the character with the maximum
2100     * bounds as defined in the specified <code>FontRenderContext</code>.
2101     * @param frc the specified <code>FontRenderContext</code>
2102     * @return a <code>Rectangle2D</code> that is the bounding box
2103     * for the character with the maximum bounds.
2104     */

2105    public Rectangle2D JavaDoc getMaxCharBounds(FontRenderContext JavaDoc frc) {
2106        float [] metrics = new float[4];
2107
2108    getFont2D().getFontMetrics(this, frc, metrics);
2109
2110        return new Rectangle2D.Float JavaDoc(0, -metrics[0],
2111                                metrics[3],
2112                                metrics[0] + metrics[1] + metrics[2]);
2113    }
2114
2115    /**
2116     * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2117     * mapping characters to glyphs one-to-one based on the
2118     * Unicode cmap in this <code>Font</code>. This method does no other
2119     * processing besides the mapping of glyphs to characters. This
2120     * means that this method is not useful for some scripts, such
2121     * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2122     * shaping, or ligature substitution.
2123     * @param frc the specified <code>FontRenderContext</code>
2124     * @param str the specified <code>String</code>
2125     * @return a new <code>GlyphVector</code> created with the
2126     * specified <code>String</code> and the specified
2127     * <code>FontRenderContext</code>.
2128     */

2129    public GlyphVector JavaDoc createGlyphVector(FontRenderContext JavaDoc frc, String JavaDoc str)
2130    {
2131        return (GlyphVector JavaDoc)new StandardGlyphVector(this, str, frc);
2132    }
2133
2134    /**
2135     * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2136     * mapping characters to glyphs one-to-one based on the
2137     * Unicode cmap in this <code>Font</code>. This method does no other
2138     * processing besides the mapping of glyphs to characters. This
2139     * means that this method is not useful for some scripts, such
2140     * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2141     * shaping, or ligature substitution.
2142     * @param frc the specified <code>FontRenderContext</code>
2143     * @param chars the specified array of characters
2144     * @return a new <code>GlyphVector</code> created with the
2145     * specified array of characters and the specified
2146     * <code>FontRenderContext</code>.
2147     */

2148    public GlyphVector JavaDoc createGlyphVector(FontRenderContext JavaDoc frc, char[] chars)
2149    {
2150        return (GlyphVector JavaDoc)new StandardGlyphVector(this, chars, frc);
2151    }
2152
2153    /**
2154     * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2155     * mapping the specified characters to glyphs one-to-one based on the
2156     * Unicode cmap in this <code>Font</code>. This method does no other
2157     * processing besides the mapping of glyphs to characters. This
2158     * means that this method is not useful for some scripts, such
2159     * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2160     * shaping, or ligature substitution.
2161     * @param frc the specified <code>FontRenderContext</code>
2162     * @param ci the specified <code>CharacterIterator</code>
2163     * @return a new <code>GlyphVector</code> created with the
2164     * specified <code>CharacterIterator</code> and the specified
2165     * <code>FontRenderContext</code>.
2166     */

2167    public GlyphVector JavaDoc createGlyphVector( FontRenderContext JavaDoc frc,
2168                                            CharacterIterator JavaDoc ci)
2169    {
2170        return (GlyphVector JavaDoc)new StandardGlyphVector(this, ci, frc);
2171    }
2172
2173    /**
2174     * Creates a {@link java.awt.font.GlyphVector GlyphVector} by
2175     * mapping characters to glyphs one-to-one based on the
2176     * Unicode cmap in this <code>Font</code>. This method does no other
2177     * processing besides the mapping of glyphs to characters. This
2178     * means that this method is not useful for some scripts, such
2179     * as Arabic, Hebrew, Thai, and Indic, that require reordering,
2180     * shaping, or ligature substitution.
2181     * @param frc the specified <code>FontRenderContext</code>
2182     * @param glyphCodes the specified integer array
2183     * @return a new <code>GlyphVector</code> created with the
2184     * specified integer array and the specified
2185     * <code>FontRenderContext</code>.
2186     */

2187    public GlyphVector JavaDoc createGlyphVector( FontRenderContext JavaDoc frc,
2188                                            int [] glyphCodes)
2189    {
2190        return (GlyphVector JavaDoc)new StandardGlyphVector(this, glyphCodes, frc);
2191    }
2192
2193    /**
2194     * Returns a new <code>GlyphVector</code> object, performing full
2195     * layout of the text if possible. Full layout is required for
2196     * complex text, such as Arabic or Hindi. Support for different
2197     * scripts depends on the font and implementation.
2198     * <p
2199     * Layout requires bidi analysis, as performed by
2200     * <code>Bidi</code>, and should only be performed on text that
2201     * has a uniform direction. The direction is indicated in the
2202     * flags parameter,by using LAYOUT_RIGHT_TO_LEFT to indicate a
2203     * right-to-left (Arabic and Hebrew) run direction, or
2204     * LAYOUT_LEFT_TO_RIGHT to indicate a left-to-right (English)
2205     * run direction.
2206     * <p>
2207     * In addition, some operations, such as Arabic shaping, require
2208     * context, so that the characters at the start and limit can have
2209     * the proper shapes. Sometimes the data in the buffer outside
2210     * the provided range does not have valid data. The values
2211     * LAYOUT_NO_START_CONTEXT and LAYOUT_NO_LIMIT_CONTEXT can be
2212     * added to the flags parameter to indicate that the text before
2213     * start, or after limit, respectively, should not be examined
2214     * for context.
2215     * <p>
2216     * All other values for the flags parameter are reserved.
2217     *
2218     * @param frc the specified <code>FontRenderContext</code>
2219     * @param text the text to layout
2220     * @param start the start of the text to use for the <code>GlyphVector</code>
2221     * @param limit the limit of the text to use for the <code>GlyphVector</code>
2222     * @param flags control flags as described above
2223     * @return a new <code>GlyphVector</code> representing the text between
2224     * start and limit, with glyphs chosen and positioned so as to best represent
2225     * the text
2226     * @throws ArrayIndexOutOfBoundsException if start or limit is
2227     * out of bounds
2228     * @see java.text.Bidi
2229     * @see #LAYOUT_LEFT_TO_RIGHT
2230     * @see #LAYOUT_RIGHT_TO_LEFT
2231     * @see #LAYOUT_NO_START_CONTEXT
2232     * @see #LAYOUT_NO_LIMIT_CONTEXT
2233     */

2234    public GlyphVector JavaDoc layoutGlyphVector(FontRenderContext JavaDoc frc,
2235                     char[] text,
2236                     int start,
2237                     int limit,
2238                     int flags) {
2239
2240      GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines
2241
StandardGlyphVector gv = gl.layout(this, frc, text,
2242                     start, limit, flags, null);
2243      GlyphLayout.done(gl);
2244      return gv;
2245    }
2246
2247    /**
2248     * A flag to layoutGlyphVector indicating that text is left-to-right as
2249     * determined by Bidi analysis.
2250     */

2251    public static final int LAYOUT_LEFT_TO_RIGHT = 0;
2252
2253    /**
2254     * A flag to layoutGlyphVector indicating that text is right-to-left as
2255     * determined by Bidi analysis.
2256     */

2257    public static final int LAYOUT_RIGHT_TO_LEFT = 1;
2258
2259    /**
2260     * A flag to layoutGlyphVector indicating that text in the char array
2261     * before the indicated start should not be examined.
2262     */

2263    public static final int LAYOUT_NO_START_CONTEXT = 2;
2264
2265    /**
2266     * A flag to layoutGlyphVector indicating that text in the char array
2267     * after the indicated limit should not be examined.
2268     */

2269    public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
2270
2271
2272    private static void applyTransform(AffineTransform JavaDoc trans, Map JavaDoc attributes) {
2273    if (trans == null) {
2274        throw new IllegalArgumentException JavaDoc("transform must not be null");
2275    }
2276    if (trans.isIdentity()) {
2277        attributes.remove(TextAttribute.TRANSFORM);
2278    } else {
2279        attributes.put(TextAttribute.TRANSFORM, new TransformAttribute JavaDoc(trans));
2280    }
2281    }
2282
2283    private static void applyStyle(int style, Map JavaDoc attributes) {
2284        if ((style & BOLD) != 0) {
2285            attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
2286        } else {
2287            attributes.remove(TextAttribute.WEIGHT);
2288        }
2289
2290        if ((style & ITALIC) != 0) {
2291            attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
2292        } else {
2293            attributes.remove(TextAttribute.POSTURE);
2294        }
2295    }
2296
2297    private static void applySize(float size, Map JavaDoc attributes) {
2298        attributes.put(TextAttribute.SIZE, new Float JavaDoc(size));
2299    }
2300
2301    /*
2302     * Initialize JNI field and method IDs
2303     */

2304    private static native void initIDs();
2305    private native void pDispose();
2306
2307    /**
2308     * Disposes the native <code>Font</code> object.
2309     */

2310    protected void finalize() throws Throwable JavaDoc {
2311        if (this.peer != null) {
2312            pDispose();
2313        }
2314        super.finalize();
2315    }
2316}
2317
Popular Tags