13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.awt;
27
28 import java.awt.font.FontRenderContext;
29 import java.awt.font.GlyphVector;
30 import java.awt.font.LineMetrics;
31 import java.awt.font.TextAttribute;
32 import java.awt.font.TextLayout;
33 import java.awt.font.TransformAttribute;
34 import java.awt.geom.AffineTransform;
35 import java.awt.geom.Point2D;
36 import java.awt.geom.Rectangle2D;
37 import java.awt.peer.FontPeer;
38 import java.io.*;
39 import java.lang.ref.SoftReference;
40 import java.security.AccessController;
41 import java.security.PrivilegedExceptionAction;
42 import java.text.AttributedCharacterIterator.Attribute;
43 import java.text.CharacterIterator;
44 import java.text.StringCharacterIterator;
45 import java.util.HashMap;
46 import java.util.Hashtable;
47 import java.util.Locale;
48 import java.util.Map;
49 import sun.font.StandardGlyphVector;
50 import sun.java2d.FontSupport;
51
52 import sun.font.AttributeMap;
53 import sun.font.AttributeValues;
54 import sun.font.EAttribute;
55 import sun.font.CompositeFont;
56 import sun.font.CreatedFontTracker;
57 import sun.font.Font2D;
58 import sun.font.Font2DHandle;
59 import sun.font.FontManager;
60 import sun.font.GlyphLayout;
61 import sun.font.FontLineMetrics;
62 import sun.font.CoreMetrics;
63
64 import static sun.font.EAttribute.*;
65
66 /**
67 * The <code>Font</code> class represents fonts, which are used to
68 * render text in a visible way.
69 * A font provides the information needed to map sequences of
70 * <em>characters</em> to sequences of <em>glyphs</em>
71 * and to render sequences of glyphs on <code>Graphics</code> and
72 * <code>Component</code> objects.
73 *
74 * <h4>Characters and Glyphs</h4>
75 *
76 * A <em>character</em> is a symbol that represents an item such as a letter,
77 * a digit, or punctuation in an abstract way. For example, <code>'g'</code>,
78 * <font size=-1>LATIN SMALL LETTER G</font>, is a character.
79 * <p>
206 * java.awt.font.TextAttribute#FONT} for more information.</p>
207 *
208 * <p>Several attributes will cause additional rendering overhead
209 * and potentially invoke layout. If a <code>Font</code> has such
210 * attributes, the <code>{@link #hasLayoutAttributes()}</code> method
211 * will return true.</p>
212 *
213 * <p>Note: Font rotations can cause text baselines to be rotated. In
214 * order to account for this (rare) possibility, font APIs are
215 * specified to return metrics and take parameters 'in
216 * baseline-relative coordinates'. This maps the 'x' coordinate to
217 * the advance along the baseline, (positive x is forward along the
218 * baseline), and the 'y' coordinate to a distance along the
219 * perpendicular to the baseline at 'x' (positive y is 90 degrees
220 * clockwise from the baseline vector). APIs for which this is
221 * especially important are called out as having 'baseline-relative
222 * coordinates.'
223 */
224 public class Font implements java.io.Serializable
225 {
226 static {
227 /* ensure that the necessary native libraries are loaded */
228 Toolkit.loadLibraries();
229 initIDs();
230 }
231
232 /**
233 * This is now only used during serialization. Typically
234 * it is null.
235 *
236 * @serial
237 * @see #getAttributes()
238 */
239 private Hashtable fRequestedAttributes;
240
241 /*
242 * Constants to be used for logical font family names.
243 */
244
245 /**
246 * A String constant for the canonical family name of the
247 * logical font "Dialog". It is useful in Font construction
248 * to provide compile-time verification of the name.
249 * @since 1.6
447 if (values == null) {
448 AttributeValues valuesTmp = new AttributeValues();
449 valuesTmp.setFamily(name);
450 valuesTmp.setSize(pointSize); // expects the float value.
451
452 if ((style & BOLD) != 0) {
453 valuesTmp.setWeight(2); // WEIGHT_BOLD
454 }
455
456 if ((style & ITALIC) != 0) {
457 valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE
458 }
459 valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility
460 values = valuesTmp;
461 }
462
463 return values;
464 }
465
466 private Font2D getFont2D() {
467 if (FontManager.usingPerAppContextComposites &&
468 font2DHandle != null &&
469 font2DHandle.font2D instanceof CompositeFont &&
470 ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) {
471 return FontManager.findFont2D(name, style,
472 FontManager.LOGICAL_FALLBACK);
473 } else if (font2DHandle == null) {
474 font2DHandle =
475 FontManager.findFont2D(name, style,
476 FontManager.LOGICAL_FALLBACK).handle;
477 }
478 /* Do not cache the de-referenced font2D. It must be explicitly
479 * de-referenced to pick up a valid font in the event that the
480 * original one is marked invalid
481 */
482 return font2DHandle.font2D;
483 }
484
485 /**
486 * Creates a new <code>Font</code> from the specified name, style and
487 * point size.
488 * <p>
489 * The font name can be a font face name or a font family name.
490 * It is used together with the style to find an appropriate font face.
491 * When a font family name is specified, the style argument is used to
492 * select the most appropriate face from the family. When a font face
493 * name is specified, the face's style and the style argument are
494 * merged to locate the best matching font from the same family.
495 * For example if face name "Arial Bold" is specified with style
553 this.pointSize = sizePts;
554 }
555
556 /* This constructor is used by deriveFont when attributes is null */
557 private Font(String name, int style, float sizePts,
558 boolean created, Font2DHandle handle) {
559 this(name, style, sizePts);
560 this.createdFont = created;
561 /* Fonts created from a stream will use the same font2D instance
562 * as the parent.
563 * One exception is that if the derived font is requested to be
564 * in a different style, then also check if its a CompositeFont
565 * and if so build a new CompositeFont from components of that style.
566 * CompositeFonts can only be marked as "created" if they are used
567 * to add fall backs to a physical font. And non-composites are
568 * always from "Font.createFont()" and shouldn't get this treatment.
569 */
570 if (created) {
571 if (handle.font2D instanceof CompositeFont &&
572 handle.font2D.getStyle() != style) {
573 this.font2DHandle =
574 FontManager.getNewComposite(null, style, handle);
575 } else {
576 this.font2DHandle = handle;
577 }
578 }
579 }
580
581 /* used to implement Font.createFont */
582 private Font(File fontFile, int fontFormat,
583 boolean isCopy, CreatedFontTracker tracker)
584 throws FontFormatException {
585 this.createdFont = true;
586 /* Font2D instances created by this method track their font file
587 * so that when the Font2D is GC'd it can also remove the file.
588 */
589 this.font2DHandle =
590 FontManager.createFont2D(fontFile, fontFormat,
591 isCopy, tracker).handle;
592 this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
593 this.style = Font.PLAIN;
594 this.size = 1;
595 this.pointSize = 1f;
596 }
597
598 /* This constructor is used when one font is derived from another.
599 * Fonts created from a stream will use the same font2D instance as the
600 * parent. They can be distinguished because the "created" argument
601 * will be "true". Since there is no way to recreate these fonts they
602 * need to have the handle to the underlying font2D passed in.
603 * "created" is also true when a special composite is referenced by the
604 * handle for essentially the same reasons.
605 * But when deriving a font in these cases two particular attributes
606 * need special attention: family/face and style.
607 * The "composites" in these cases need to be recreated with optimal
608 * fonts for the new values of family and style.
609 * For fonts created with createFont() these are treated differently.
610 * JDK can often synthesise a different style (bold from plain
611 * for example). For fonts created with "createFont" this is a reasonable
623
624 this.createdFont = created;
625 if (created) {
626 this.font2DHandle = handle;
627
628 String newName = null;
629 if (oldName != null) {
630 newName = values.getFamily();
631 if (oldName.equals(newName)) newName = null;
632 }
633 int newStyle = 0;
634 if (oldStyle == -1) {
635 newStyle = -1;
636 } else {
637 if (values.getWeight() >= 2f) newStyle = BOLD;
638 if (values.getPosture() >= .2f) newStyle |= ITALIC;
639 if (oldStyle == newStyle) newStyle = -1;
640 }
641 if (handle.font2D instanceof CompositeFont) {
642 if (newStyle != -1 || newName != null) {
643 this.font2DHandle =
644 FontManager.getNewComposite(newName, newStyle, handle);
645 }
646 } else if (newName != null) {
647 this.createdFont = false;
648 this.font2DHandle = null;
649 }
650 }
651 initFromValues(values);
652 }
653
654 /**
655 * Creates a new <code>Font</code> with the specified attributes.
656 * Only keys defined in {@link java.awt.font.TextAttribute TextAttribute}
657 * are recognized. In addition the FONT attribute is
658 * not recognized by this constructor
659 * (see {@link #getAvailableAttributes}). Only attributes that have
660 * values of valid types will affect the new <code>Font</code>.
661 * <p>
662 * If <code>attributes</code> is <code>null</code>, a new
663 * <code>Font</code> is initialized with default values.
664 * @see java.awt.font.TextAttribute
835 * @param fontStream an <code>InputStream</code> object representing the
836 * input data for the font.
837 * @return a new <code>Font</code> created with the specified font type.
838 * @throws IllegalArgumentException if <code>fontFormat</code> is not
839 * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
840 * @throws FontFormatException if the <code>fontStream</code> data does
841 * not contain the required font tables for the specified format.
842 * @throws IOException if the <code>fontStream</code>
843 * cannot be completely read.
844 * @see GraphicsEnvironment#registerFont(Font)
845 * @since 1.3
846 */
847 public static Font createFont(int fontFormat, InputStream fontStream)
848 throws java.awt.FontFormatException, java.io.IOException {
849
850 if (fontFormat != Font.TRUETYPE_FONT &&
851 fontFormat != Font.TYPE1_FONT) {
852 throw new IllegalArgumentException ("font format not recognized");
853 }
854 boolean copiedFontData = false;
855
856 try {
857 final File tFile = AccessController.doPrivileged(
858 new PrivilegedExceptionAction<File>() {
859 public File run() throws IOException {
860 return File.createTempFile("+~JF", ".tmp", null);
861 }
862 }
863 );
864
865 int totalSize = 0;
866 CreatedFontTracker tracker = null;
867 try {
868 final OutputStream outStream =
869 AccessController.doPrivileged(
870 new PrivilegedExceptionAction<OutputStream>() {
871 public OutputStream run() throws IOException {
872 return new FileOutputStream(tFile);
873 }
874 }
875 );
2303 int beginIndex, int limit,
2304 FontRenderContext frc) {
2305 if (beginIndex < 0) {
2306 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
2307 }
2308 if (limit > chars.length) {
2309 throw new IndexOutOfBoundsException("limit: " + limit);
2310 }
2311 if (beginIndex > limit) {
2312 throw new IndexOutOfBoundsException("range length: " +
2313 (limit - beginIndex));
2314 }
2315
2316 // this code should be in textlayout
2317 // quick check for simple text, assume GV ok to use if simple
2318
2319 boolean simple = values == null ||
2320 (values.getKerning() == 0 && values.getLigatures() == 0 &&
2321 values.getBaselineTransform() == null);
2322 if (simple) {
2323 simple = !FontManager.isComplexText(chars, beginIndex, limit);
2324 }
2325
2326 if (simple) {
2327 GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex,
2328 limit - beginIndex, frc);
2329 return gv.getLogicalBounds();
2330 } else {
2331 // need char array constructor on textlayout
2332 String str = new String(chars, beginIndex, limit - beginIndex);
2333 TextLayout tl = new TextLayout(str, this, frc);
2334 return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
2335 tl.getAscent() + tl.getDescent() +
2336 tl.getLeading());
2337 }
2338 }
2339
2340 /**
2341 * Returns the logical bounds of the characters indexed in the
2342 * specified {@link CharacterIterator} in the
2343 * specified <code>FontRenderContext</code>. The logical bounds
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.awt;
27
28 import java.awt.font.FontRenderContext;
29 import java.awt.font.GlyphVector;
30 import java.awt.font.LineMetrics;
31 import java.awt.font.TextAttribute;
32 import java.awt.font.TextLayout;
33 import java.awt.geom.AffineTransform;
34 import java.awt.geom.Point2D;
35 import java.awt.geom.Rectangle2D;
36 import java.awt.peer.FontPeer;
37 import java.io.*;
38 import java.lang.ref.SoftReference;
39 import java.security.AccessController;
40 import java.security.PrivilegedExceptionAction;
41 import java.text.AttributedCharacterIterator.Attribute;
42 import java.text.CharacterIterator;
43 import java.text.StringCharacterIterator;
44 import java.util.Hashtable;
45 import java.util.Locale;
46 import java.util.Map;
47 import sun.font.StandardGlyphVector;
48
49 import sun.font.AttributeMap;
50 import sun.font.AttributeValues;
51 import sun.font.CompositeFont;
52 import sun.font.CreatedFontTracker;
53 import sun.font.Font2D;
54 import sun.font.Font2DHandle;
55 import sun.font.FontAccess;
56 import sun.font.FontManager;
57 import sun.font.FontManagerFactory;
58 import sun.font.FontUtilities;
59 import sun.font.GlyphLayout;
60 import sun.font.FontLineMetrics;
61 import sun.font.CoreMetrics;
62
63 import static sun.font.EAttribute.*;
64
65 /**
66 * The <code>Font</code> class represents fonts, which are used to
67 * render text in a visible way.
68 * A font provides the information needed to map sequences of
69 * <em>characters</em> to sequences of <em>glyphs</em>
70 * and to render sequences of glyphs on <code>Graphics</code> and
71 * <code>Component</code> objects.
72 *
73 * <h4>Characters and Glyphs</h4>
74 *
75 * A <em>character</em> is a symbol that represents an item such as a letter,
76 * a digit, or punctuation in an abstract way. For example, <code>'g'</code>,
77 * <font size=-1>LATIN SMALL LETTER G</font>, is a character.
78 * <p>
205 * java.awt.font.TextAttribute#FONT} for more information.</p>
206 *
207 * <p>Several attributes will cause additional rendering overhead
208 * and potentially invoke layout. If a <code>Font</code> has such
209 * attributes, the <code>{@link #hasLayoutAttributes()}</code> method
210 * will return true.</p>
211 *
212 * <p>Note: Font rotations can cause text baselines to be rotated. In
213 * order to account for this (rare) possibility, font APIs are
214 * specified to return metrics and take parameters 'in
215 * baseline-relative coordinates'. This maps the 'x' coordinate to
216 * the advance along the baseline, (positive x is forward along the
217 * baseline), and the 'y' coordinate to a distance along the
218 * perpendicular to the baseline at 'x' (positive y is 90 degrees
219 * clockwise from the baseline vector). APIs for which this is
220 * especially important are called out as having 'baseline-relative
221 * coordinates.'
222 */
223 public class Font implements java.io.Serializable
224 {
225 private static class FontAccessImpl extends FontAccess {
226 public Font2D getFont2D(Font font) {
227 return font.getFont2D();
228 }
229
230 public void setFont2D(Font font, Font2DHandle handle) {
231 font.font2DHandle = handle;
232 }
233
234 public void setCreatedFont(Font font) {
235 font.createdFont = true;
236 }
237
238 public boolean isCreatedFont(Font font) {
239 return font.createdFont;
240 }
241 }
242
243 static {
244 /* ensure that the necessary native libraries are loaded */
245 Toolkit.loadLibraries();
246 initIDs();
247 FontAccess.setFontAccess(new FontAccessImpl());
248 }
249
250 /**
251 * This is now only used during serialization. Typically
252 * it is null.
253 *
254 * @serial
255 * @see #getAttributes()
256 */
257 private Hashtable fRequestedAttributes;
258
259 /*
260 * Constants to be used for logical font family names.
261 */
262
263 /**
264 * A String constant for the canonical family name of the
265 * logical font "Dialog". It is useful in Font construction
266 * to provide compile-time verification of the name.
267 * @since 1.6
465 if (values == null) {
466 AttributeValues valuesTmp = new AttributeValues();
467 valuesTmp.setFamily(name);
468 valuesTmp.setSize(pointSize); // expects the float value.
469
470 if ((style & BOLD) != 0) {
471 valuesTmp.setWeight(2); // WEIGHT_BOLD
472 }
473
474 if ((style & ITALIC) != 0) {
475 valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE
476 }
477 valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility
478 values = valuesTmp;
479 }
480
481 return values;
482 }
483
484 private Font2D getFont2D() {
485 FontManager fm = FontManagerFactory.getInstance();
486 if (fm.usingPerAppContextComposites() &&
487 font2DHandle != null &&
488 font2DHandle.font2D instanceof CompositeFont &&
489 ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) {
490 return fm.findFont2D(name, style,
491 FontManager.LOGICAL_FALLBACK);
492 } else if (font2DHandle == null) {
493 font2DHandle =
494 fm.findFont2D(name, style,
495 FontManager.LOGICAL_FALLBACK).handle;
496 }
497 /* Do not cache the de-referenced font2D. It must be explicitly
498 * de-referenced to pick up a valid font in the event that the
499 * original one is marked invalid
500 */
501 return font2DHandle.font2D;
502 }
503
504 /**
505 * Creates a new <code>Font</code> from the specified name, style and
506 * point size.
507 * <p>
508 * The font name can be a font face name or a font family name.
509 * It is used together with the style to find an appropriate font face.
510 * When a font family name is specified, the style argument is used to
511 * select the most appropriate face from the family. When a font face
512 * name is specified, the face's style and the style argument are
513 * merged to locate the best matching font from the same family.
514 * For example if face name "Arial Bold" is specified with style
572 this.pointSize = sizePts;
573 }
574
575 /* This constructor is used by deriveFont when attributes is null */
576 private Font(String name, int style, float sizePts,
577 boolean created, Font2DHandle handle) {
578 this(name, style, sizePts);
579 this.createdFont = created;
580 /* Fonts created from a stream will use the same font2D instance
581 * as the parent.
582 * One exception is that if the derived font is requested to be
583 * in a different style, then also check if its a CompositeFont
584 * and if so build a new CompositeFont from components of that style.
585 * CompositeFonts can only be marked as "created" if they are used
586 * to add fall backs to a physical font. And non-composites are
587 * always from "Font.createFont()" and shouldn't get this treatment.
588 */
589 if (created) {
590 if (handle.font2D instanceof CompositeFont &&
591 handle.font2D.getStyle() != style) {
592 FontManager fm = FontManagerFactory.getInstance();
593 this.font2DHandle = fm.getNewComposite(null, style, handle);
594 } else {
595 this.font2DHandle = handle;
596 }
597 }
598 }
599
600 /* used to implement Font.createFont */
601 private Font(File fontFile, int fontFormat,
602 boolean isCopy, CreatedFontTracker tracker)
603 throws FontFormatException {
604 this.createdFont = true;
605 /* Font2D instances created by this method track their font file
606 * so that when the Font2D is GC'd it can also remove the file.
607 */
608 FontManager fm = FontManagerFactory.getInstance();
609 this.font2DHandle = fm.createFont2D(fontFile, fontFormat, isCopy,
610 tracker).handle;
611 this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
612 this.style = Font.PLAIN;
613 this.size = 1;
614 this.pointSize = 1f;
615 }
616
617 /* This constructor is used when one font is derived from another.
618 * Fonts created from a stream will use the same font2D instance as the
619 * parent. They can be distinguished because the "created" argument
620 * will be "true". Since there is no way to recreate these fonts they
621 * need to have the handle to the underlying font2D passed in.
622 * "created" is also true when a special composite is referenced by the
623 * handle for essentially the same reasons.
624 * But when deriving a font in these cases two particular attributes
625 * need special attention: family/face and style.
626 * The "composites" in these cases need to be recreated with optimal
627 * fonts for the new values of family and style.
628 * For fonts created with createFont() these are treated differently.
629 * JDK can often synthesise a different style (bold from plain
630 * for example). For fonts created with "createFont" this is a reasonable
642
643 this.createdFont = created;
644 if (created) {
645 this.font2DHandle = handle;
646
647 String newName = null;
648 if (oldName != null) {
649 newName = values.getFamily();
650 if (oldName.equals(newName)) newName = null;
651 }
652 int newStyle = 0;
653 if (oldStyle == -1) {
654 newStyle = -1;
655 } else {
656 if (values.getWeight() >= 2f) newStyle = BOLD;
657 if (values.getPosture() >= .2f) newStyle |= ITALIC;
658 if (oldStyle == newStyle) newStyle = -1;
659 }
660 if (handle.font2D instanceof CompositeFont) {
661 if (newStyle != -1 || newName != null) {
662 FontManager fm = FontManagerFactory.getInstance();
663 this.font2DHandle =
664 fm.getNewComposite(newName, newStyle, handle);
665 }
666 } else if (newName != null) {
667 this.createdFont = false;
668 this.font2DHandle = null;
669 }
670 }
671 initFromValues(values);
672 }
673
674 /**
675 * Creates a new <code>Font</code> with the specified attributes.
676 * Only keys defined in {@link java.awt.font.TextAttribute TextAttribute}
677 * are recognized. In addition the FONT attribute is
678 * not recognized by this constructor
679 * (see {@link #getAvailableAttributes}). Only attributes that have
680 * values of valid types will affect the new <code>Font</code>.
681 * <p>
682 * If <code>attributes</code> is <code>null</code>, a new
683 * <code>Font</code> is initialized with default values.
684 * @see java.awt.font.TextAttribute
855 * @param fontStream an <code>InputStream</code> object representing the
856 * input data for the font.
857 * @return a new <code>Font</code> created with the specified font type.
858 * @throws IllegalArgumentException if <code>fontFormat</code> is not
859 * <code>TRUETYPE_FONT</code>or<code>TYPE1_FONT</code>.
860 * @throws FontFormatException if the <code>fontStream</code> data does
861 * not contain the required font tables for the specified format.
862 * @throws IOException if the <code>fontStream</code>
863 * cannot be completely read.
864 * @see GraphicsEnvironment#registerFont(Font)
865 * @since 1.3
866 */
867 public static Font createFont(int fontFormat, InputStream fontStream)
868 throws java.awt.FontFormatException, java.io.IOException {
869
870 if (fontFormat != Font.TRUETYPE_FONT &&
871 fontFormat != Font.TYPE1_FONT) {
872 throw new IllegalArgumentException ("font format not recognized");
873 }
874 boolean copiedFontData = false;
875 try {
876 final File tFile = AccessController.doPrivileged(
877 new PrivilegedExceptionAction<File>() {
878 public File run() throws IOException {
879 return File.createTempFile("+~JF", ".tmp", null);
880 }
881 }
882 );
883
884 int totalSize = 0;
885 CreatedFontTracker tracker = null;
886 try {
887 final OutputStream outStream =
888 AccessController.doPrivileged(
889 new PrivilegedExceptionAction<OutputStream>() {
890 public OutputStream run() throws IOException {
891 return new FileOutputStream(tFile);
892 }
893 }
894 );
2322 int beginIndex, int limit,
2323 FontRenderContext frc) {
2324 if (beginIndex < 0) {
2325 throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
2326 }
2327 if (limit > chars.length) {
2328 throw new IndexOutOfBoundsException("limit: " + limit);
2329 }
2330 if (beginIndex > limit) {
2331 throw new IndexOutOfBoundsException("range length: " +
2332 (limit - beginIndex));
2333 }
2334
2335 // this code should be in textlayout
2336 // quick check for simple text, assume GV ok to use if simple
2337
2338 boolean simple = values == null ||
2339 (values.getKerning() == 0 && values.getLigatures() == 0 &&
2340 values.getBaselineTransform() == null);
2341 if (simple) {
2342 simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);
2343 }
2344
2345 if (simple) {
2346 GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex,
2347 limit - beginIndex, frc);
2348 return gv.getLogicalBounds();
2349 } else {
2350 // need char array constructor on textlayout
2351 String str = new String(chars, beginIndex, limit - beginIndex);
2352 TextLayout tl = new TextLayout(str, this, frc);
2353 return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
2354 tl.getAscent() + tl.getDescent() +
2355 tl.getLeading());
2356 }
2357 }
2358
2359 /**
2360 * Returns the logical bounds of the characters indexed in the
2361 * specified {@link CharacterIterator} in the
2362 * specified <code>FontRenderContext</code>. The logical bounds
|