1 /*
   2  * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt;
  27 
  28 import java.awt.Graphics2D;
  29 import java.awt.font.FontRenderContext;
  30 import java.awt.font.LineMetrics;
  31 import java.awt.geom.Rectangle2D;
  32 import java.text.CharacterIterator;
  33 
  34 /**
  35  * The {@code FontMetrics} class defines a font metrics object, which
  36  * encapsulates information about the rendering of a particular font on a
  37  * particular screen.
  38  * <p>
  39  * <b>Note to subclassers</b>: Since many of these methods form closed,
  40  * mutually recursive loops, you must take care that you implement
  41  * at least one of the methods in each such loop to prevent
  42  * infinite recursion when your subclass is used.
  43  * In particular, the following is the minimal suggested set of methods
  44  * to override in order to ensure correctness and prevent infinite
  45  * recursion (though other subsets are equally feasible):
  46  * <ul>
  47  * <li>{@link #getAscent()}
  48  * <li>{@link #getLeading()}
  49  * <li>{@link #getMaxAdvance()}
  50  * <li>{@link #charWidth(char)}
  51  * <li>{@link #charsWidth(char[], int, int)}
  52  * </ul>
  53  * <p>
  54  * <img src="doc-files/FontMetrics-1.gif" alt="The letter 'p' showing its 'reference point'"
  55  * style="border:15px; float:right; margin: 7px 10px;">
  56  * Note that the implementations of these methods are
  57  * inefficient, so they are usually overridden with more efficient
  58  * toolkit-specific implementations.
  59  * <p>
  60  * When an application asks to place a character at the position
  61  * (<i>x</i>,&nbsp;<i>y</i>), the character is placed so that its
  62  * reference point (shown as the dot in the accompanying image) is
  63  * put at that position. The reference point specifies a horizontal
  64  * line called the <i>baseline</i> of the character. In normal
  65  * printing, the baselines of characters should align.
  66  * <p>
  67  * In addition, every character in a font has an <i>ascent</i>, a
  68  * <i>descent</i>, and an <i>advance width</i>. The ascent is the
  69  * amount by which the character ascends above the baseline. The
  70  * descent is the amount by which the character descends below the
  71  * baseline. The advance width indicates the position at which AWT
  72  * should place the next character.
  73  * <p>
  74  * An array of characters or a string can also have an ascent, a
  75  * descent, and an advance width. The ascent of the array is the
  76  * maximum ascent of any character in the array. The descent is the
  77  * maximum descent of any character in the array. The advance width
  78  * is the sum of the advance widths of each of the characters in the
  79  * character array.  The advance of a {@code String} is the
  80  * distance along the baseline of the {@code String}.  This
  81  * distance is the width that should be used for centering or
  82  * right-aligning the {@code String}.
  83  * <p>Note that the advance of a {@code String} is not necessarily
  84  * the sum of the advances of its characters measured in isolation
  85  * because the width of a character can vary depending on its context.
  86  * For example, in Arabic text, the shape of a character can change
  87  * in order to connect to other characters.  Also, in some scripts,
  88  * certain character sequences can be represented by a single shape,
  89  * called a <em>ligature</em>.  Measuring characters individually does
  90  * not account for these transformations.
  91  * <p>Font metrics are baseline-relative, meaning that they are
  92  * generally independent of the rotation applied to the font (modulo
  93  * possible grid hinting effects).  See {@link java.awt.Font Font}.
  94  *
  95  * @author      Jim Graham
  96  * @see         java.awt.Font
  97  * @since       1.0
  98  */
  99 public abstract class FontMetrics implements java.io.Serializable {
 100 
 101     static {
 102         /* ensure that the necessary native libraries are loaded */
 103         Toolkit.loadLibraries();
 104         if (!GraphicsEnvironment.isHeadless()) {
 105             initIDs();
 106         }
 107     }
 108 
 109     private static final FontRenderContext
 110         DEFAULT_FRC = new FontRenderContext(null, false, false);
 111 
 112     /**
 113      * The actual {@link Font} from which the font metrics are
 114      * created.
 115      * This cannot be null.
 116      *
 117      * @serial
 118      * @see #getFont()
 119      */
 120     protected Font font;
 121 
 122     /*
 123      * JDK 1.1 serialVersionUID
 124      */
 125     private static final long serialVersionUID = 1681126225205050147L;
 126 
 127     /**
 128      * Creates a new {@code FontMetrics} object for finding out
 129      * height and width information about the specified {@code Font}
 130      * and specific character glyphs in that {@code Font}.
 131      * @param     font the {@code Font}
 132      * @see       java.awt.Font
 133      */
 134     protected FontMetrics(Font font) {
 135         this.font = font;
 136     }
 137 
 138     /**
 139      * Gets the {@code Font} described by this
 140      * {@code FontMetrics} object.
 141      * @return    the {@code Font} described by this
 142      * {@code FontMetrics} object.
 143      */
 144     public Font getFont() {
 145         return font;
 146     }
 147 
 148     /**
 149      * Gets the {@code FontRenderContext} used by this
 150      * {@code FontMetrics} object to measure text.
 151      * <p>
 152      * Note that methods in this class which take a {@code Graphics}
 153      * parameter measure text using the {@code FontRenderContext}
 154      * of that {@code Graphics} object, and not this
 155      * {@code FontRenderContext}
 156      * @return    the {@code FontRenderContext} used by this
 157      * {@code FontMetrics} object.
 158      * @since 1.6
 159      */
 160     public FontRenderContext getFontRenderContext() {
 161         return DEFAULT_FRC;
 162     }
 163 
 164     /**
 165      * Determines the <em>standard leading</em> of the
 166      * {@code Font} described by this {@code FontMetrics}
 167      * object.  The standard leading, or
 168      * interline spacing, is the logical amount of space to be reserved
 169      * between the descent of one line of text and the ascent of the next
 170      * line. The height metric is calculated to include this extra space.
 171      * @return    the standard leading of the {@code Font}.
 172      * @see   #getHeight()
 173      * @see   #getAscent()
 174      * @see   #getDescent()
 175      */
 176     public int getLeading() {
 177         return 0;
 178     }
 179 
 180     /**
 181      * Determines the <em>font ascent</em> of the {@code Font}
 182      * described by this {@code FontMetrics} object. The font ascent
 183      * is the distance from the font's baseline to the top of most
 184      * alphanumeric characters. Some characters in the {@code Font}
 185      * might extend above the font ascent line.
 186      * @return     the font ascent of the {@code Font}.
 187      * @see        #getMaxAscent()
 188      */
 189     public int getAscent() {
 190         return font.getSize();
 191     }
 192 
 193     /**
 194      * Determines the <em>font descent</em> of the {@code Font}
 195      * described by this
 196      * {@code FontMetrics} object. The font descent is the distance
 197      * from the font's baseline to the bottom of most alphanumeric
 198      * characters with descenders. Some characters in the
 199      * {@code Font} might extend
 200      * below the font descent line.
 201      * @return     the font descent of the {@code Font}.
 202      * @see        #getMaxDescent()
 203      */
 204     public int getDescent() {
 205         return 0;
 206     }
 207 
 208     /**
 209      * Gets the standard height of a line of text in this font.  This
 210      * is the distance between the baseline of adjacent lines of text.
 211      * It is the sum of the leading + ascent + descent. Due to rounding
 212      * this may not be the same as getAscent() + getDescent() + getLeading().
 213      * There is no guarantee that lines of text spaced at this distance are
 214      * disjoint; such lines may overlap if some characters overshoot
 215      * either the standard ascent or the standard descent metric.
 216      * @return    the standard height of the font.
 217      * @see       #getLeading()
 218      * @see       #getAscent()
 219      * @see       #getDescent()
 220      */
 221     public int getHeight() {
 222         return getLeading() + getAscent() + getDescent();
 223     }
 224 
 225     /**
 226      * Determines the maximum ascent of the {@code Font}
 227      * described by this {@code FontMetrics} object.  No character
 228      * extends further above the font's baseline than this height.
 229      * @return    the maximum ascent of any character in the
 230      * {@code Font}.
 231      * @see       #getAscent()
 232      */
 233     public int getMaxAscent() {
 234         return getAscent();
 235     }
 236 
 237     /**
 238      * Determines the maximum descent of the {@code Font}
 239      * described by this {@code FontMetrics} object.  No character
 240      * extends further below the font's baseline than this height.
 241      * @return    the maximum descent of any character in the
 242      * {@code Font}.
 243      * @see       #getDescent()
 244      */
 245     public int getMaxDescent() {
 246         return getDescent();
 247     }
 248 
 249     /**
 250      * For backward compatibility only.
 251      * @return    the maximum descent of any character in the
 252      * {@code Font}.
 253      * @see #getMaxDescent()
 254      * @deprecated As of JDK version 1.1.1,
 255      * replaced by {@code getMaxDescent()}.
 256      */
 257     @Deprecated
 258     public int getMaxDecent() {
 259         return getMaxDescent();
 260     }
 261 
 262     /**
 263      * Gets the maximum advance width of any character in this
 264      * {@code Font}.  The advance is the
 265      * distance from the leftmost point to the rightmost point on the
 266      * string's baseline.  The advance of a {@code String} is
 267      * not necessarily the sum of the advances of its characters.
 268      * @return    the maximum advance width of any character
 269      *            in the {@code Font}, or {@code -1} if the
 270      *            maximum advance width is not known.
 271      */
 272     public int getMaxAdvance() {
 273         return -1;
 274     }
 275 
 276     /**
 277      * Returns the advance width of the specified character in this
 278      * {@code Font}.  The advance is the
 279      * distance from the leftmost point to the rightmost point on the
 280      * character's baseline.  Note that the advance of a
 281      * {@code String} is not necessarily the sum of the advances
 282      * of its characters.
 283      *
 284      * <p>This method doesn't validate the specified character to be a
 285      * valid Unicode code point. The caller must validate the
 286      * character value using {@link
 287      * java.lang.Character#isValidCodePoint(int)
 288      * Character.isValidCodePoint} if necessary.
 289      *
 290      * @param codePoint the character (Unicode code point) to be measured
 291      * @return    the advance width of the specified character
 292      *            in the {@code Font} described by this
 293      *            {@code FontMetrics} object.
 294      * @see   #charsWidth(char[], int, int)
 295      * @see   #stringWidth(String)
 296      */
 297     public int charWidth(int codePoint) {
 298         if (!Character.isValidCodePoint(codePoint)) {
 299             codePoint = 0xffff; // substitute missing glyph width
 300         }
 301 
 302         if (codePoint < 256) {
 303             return getWidths()[codePoint];
 304         } else {
 305             char[] buffer = new char[2];
 306             int len = Character.toChars(codePoint, buffer, 0);
 307             return charsWidth(buffer, 0, len);
 308         }
 309     }
 310 
 311     /**
 312      * Returns the advance width of the specified character in this
 313      * {@code Font}.  The advance is the
 314      * distance from the leftmost point to the rightmost point on the
 315      * character's baseline.  Note that the advance of a
 316      * {@code String} is not necessarily the sum of the advances
 317      * of its characters.
 318      *
 319      * <p><b>Note:</b> This method cannot handle <a
 320      * href="../../../java.base/java/lang/Character.html#supplementary">
 321      * supplementary characters</a>.
 322      * To support all Unicode characters, including
 323      * supplementary characters, use the {@link #charWidth(int)} method.
 324      *
 325      * @param ch the character to be measured
 326      * @return     the advance width of the specified character
 327      *                  in the {@code Font} described by this
 328      *                  {@code FontMetrics} object.
 329      * @see        #charsWidth(char[], int, int)
 330      * @see        #stringWidth(String)
 331      */
 332     public int charWidth(char ch) {
 333         if (ch < 256) {
 334             return getWidths()[ch];
 335         }
 336         char[] data = {ch};
 337         return charsWidth(data, 0, 1);
 338     }
 339 
 340     /**
 341      * Returns the total advance width for showing the specified
 342      * {@code String} in this {@code Font}.  The advance
 343      * is the distance from the leftmost point to the rightmost point
 344      * on the string's baseline.
 345      * <p>
 346      * Note that the advance of a {@code String} is
 347      * not necessarily the sum of the advances of its characters.
 348      * @param str the {@code String} to be measured
 349      * @return    the advance width of the specified {@code String}
 350      *                  in the {@code Font} described by this
 351      *                  {@code FontMetrics}.
 352      * @throws NullPointerException if str is null.
 353      * @see       #bytesWidth(byte[], int, int)
 354      * @see       #charsWidth(char[], int, int)
 355      * @see       #getStringBounds(String, Graphics)
 356      */
 357     public int stringWidth(String str) {
 358         int len = str.length();
 359         char[] data = new char[len];
 360         str.getChars(0, len, data, 0);
 361         return charsWidth(data, 0, len);
 362     }
 363 
 364     /**
 365      * Returns the total advance width for showing the specified array
 366      * of characters in this {@code Font}.  The advance is the
 367      * distance from the leftmost point to the rightmost point on the
 368      * string's baseline.  The advance of a {@code String}
 369      * is not necessarily the sum of the advances of its characters.
 370      * This is equivalent to measuring a {@code String} of the
 371      * characters in the specified range.
 372      * @param data the array of characters to be measured
 373      * @param off the start offset of the characters in the array
 374      * @param len the number of characters to be measured from the array
 375      * @return    the advance width of the subarray of the specified
 376      *               {@code char} array in the font described by
 377      *               this {@code FontMetrics} object.
 378      * @throws    NullPointerException if {@code data} is null.
 379      * @throws    IndexOutOfBoundsException if the {@code off}
 380      *            and {@code len} arguments index characters outside
 381      *            the bounds of the {@code data} array.
 382      * @see       #charWidth(int)
 383      * @see       #charWidth(char)
 384      * @see       #bytesWidth(byte[], int, int)
 385      * @see       #stringWidth(String)
 386      */
 387     public int charsWidth(char[] data, int off, int len) {
 388         return stringWidth(new String(data, off, len));
 389     }
 390 
 391     /**
 392      * Returns the total advance width for showing the specified array
 393      * of bytes in this {@code Font}.  The advance is the
 394      * distance from the leftmost point to the rightmost point on the
 395      * string's baseline.  The advance of a {@code String}
 396      * is not necessarily the sum of the advances of its characters.
 397      * This is equivalent to measuring a {@code String} of the
 398      * characters in the specified range.
 399      * @param data the array of bytes to be measured
 400      * @param off the start offset of the bytes in the array
 401      * @param len the number of bytes to be measured from the array
 402      * @return    the advance width of the subarray of the specified
 403      *               {@code byte} array in the {@code Font}
 404      *                  described by
 405      *               this {@code FontMetrics} object.
 406      * @throws    NullPointerException if {@code data} is null.
 407      * @throws    IndexOutOfBoundsException if the {@code off}
 408      *            and {@code len} arguments index bytes outside
 409      *            the bounds of the {@code data} array.
 410      * @see       #charsWidth(char[], int, int)
 411      * @see       #stringWidth(String)
 412      */
 413     @SuppressWarnings("deprecation")
 414     public int bytesWidth(byte[] data, int off, int len) {
 415         return stringWidth(new String(data, 0, off, len));
 416     }
 417 
 418     /**
 419      * Gets the advance widths of the first 256 characters in the
 420      * {@code Font}.  The advance is the
 421      * distance from the leftmost point to the rightmost point on the
 422      * character's baseline.  Note that the advance of a
 423      * {@code String} is not necessarily the sum of the advances
 424      * of its characters.
 425      * @return    an array storing the advance widths of the
 426      *                 characters in the {@code Font}
 427      *                 described by this {@code FontMetrics} object.
 428      */
 429     public int[] getWidths() {
 430         int[] widths = new int[256];
 431         for (char ch = 0 ; ch < 256 ; ch++) {
 432             widths[ch] = charWidth(ch);
 433         }
 434         return widths;
 435     }
 436 
 437     /**
 438      * Checks to see if the {@code Font} has uniform line metrics.  A
 439      * composite font may consist of several different fonts to cover
 440      * various character sets.  In such cases, the
 441      * {@code FontLineMetrics} objects are not uniform.
 442      * Different fonts may have a different ascent, descent, metrics and
 443      * so on.  This information is sometimes necessary for line
 444      * measuring and line breaking.
 445      * @return {@code true} if the font has uniform line metrics;
 446      * {@code false} otherwise.
 447      * @see java.awt.Font#hasUniformLineMetrics()
 448      */
 449     public boolean hasUniformLineMetrics() {
 450         return font.hasUniformLineMetrics();
 451     }
 452 
 453     /**
 454      * Returns the {@link LineMetrics} object for the specified
 455      * {@code String} in the specified {@link Graphics} context.
 456      * @param str the specified {@code String}
 457      * @param context the specified {@code Graphics} context
 458      * @return a {@code LineMetrics} object created with the
 459      * specified {@code String} and {@code Graphics} context.
 460      * @see java.awt.Font#getLineMetrics(String, FontRenderContext)
 461      */
 462     public LineMetrics getLineMetrics( String str, Graphics context) {
 463         return font.getLineMetrics(str, myFRC(context));
 464     }
 465 
 466     /**
 467      * Returns the {@link LineMetrics} object for the specified
 468      * {@code String} in the specified {@link Graphics} context.
 469      * @param str the specified {@code String}
 470      * @param beginIndex the initial offset of {@code str}
 471      * @param limit the end offset of {@code str}
 472      * @param context the specified {@code Graphics} context
 473      * @return a {@code LineMetrics} object created with the
 474      * specified {@code String} and {@code Graphics} context.
 475      * @see java.awt.Font#getLineMetrics(String, int, int, FontRenderContext)
 476      */
 477     public LineMetrics getLineMetrics( String str,
 478                                             int beginIndex, int limit,
 479                                             Graphics context) {
 480         return font.getLineMetrics(str, beginIndex, limit, myFRC(context));
 481     }
 482 
 483     /**
 484      * Returns the {@link LineMetrics} object for the specified
 485      * character array in the specified {@link Graphics} context.
 486      * @param chars the specified character array
 487      * @param beginIndex the initial offset of {@code chars}
 488      * @param limit the end offset of {@code chars}
 489      * @param context the specified {@code Graphics} context
 490      * @return a {@code LineMetrics} object created with the
 491      * specified character array and {@code Graphics} context.
 492      * @see java.awt.Font#getLineMetrics(char[], int, int, FontRenderContext)
 493      */
 494     public LineMetrics getLineMetrics(char [] chars,
 495                                             int beginIndex, int limit,
 496                                             Graphics context) {
 497         return font.getLineMetrics(
 498                                 chars, beginIndex, limit, myFRC(context));
 499     }
 500 
 501     /**
 502      * Returns the {@link LineMetrics} object for the specified
 503      * {@link CharacterIterator} in the specified {@link Graphics}
 504      * context.
 505      * @param ci the specified {@code CharacterIterator}
 506      * @param beginIndex the initial offset in {@code ci}
 507      * @param limit the end index of {@code ci}
 508      * @param context the specified {@code Graphics} context
 509      * @return a {@code LineMetrics} object created with the
 510      * specified arguments.
 511      * @see java.awt.Font#getLineMetrics(CharacterIterator, int, int, FontRenderContext)
 512      */
 513     public LineMetrics getLineMetrics(CharacterIterator ci,
 514                                             int beginIndex, int limit,
 515                                             Graphics context) {
 516         return font.getLineMetrics(ci, beginIndex, limit, myFRC(context));
 517     }
 518 
 519     /**
 520      * Returns the bounds of the specified {@code String} in the
 521      * specified {@code Graphics} context.  The bounds is used
 522      * to layout the {@code String}.
 523      * <p>Note: The returned bounds is in baseline-relative coordinates
 524      * (see {@link java.awt.FontMetrics class notes}).
 525      * @param str the specified {@code String}
 526      * @param context the specified {@code Graphics} context
 527      * @return a {@link Rectangle2D} that is the bounding box of the
 528      * specified {@code String} in the specified
 529      * {@code Graphics} context.
 530      * @see java.awt.Font#getStringBounds(String, FontRenderContext)
 531      */
 532     public Rectangle2D getStringBounds( String str, Graphics context) {
 533         return font.getStringBounds(str, myFRC(context));
 534     }
 535 
 536     /**
 537      * Returns the bounds of the specified {@code String} in the
 538      * specified {@code Graphics} context.  The bounds is used
 539      * to layout the {@code String}.
 540      * <p>Note: The returned bounds is in baseline-relative coordinates
 541      * (see {@link java.awt.FontMetrics class notes}).
 542      * @param str the specified {@code String}
 543      * @param beginIndex the offset of the beginning of {@code str}
 544      * @param limit the end offset of {@code str}
 545      * @param context the specified {@code Graphics} context
 546      * @return a {@code Rectangle2D} that is the bounding box of the
 547      * specified {@code String} in the specified
 548      * {@code Graphics} context.
 549      * @see java.awt.Font#getStringBounds(String, int, int, FontRenderContext)
 550      */
 551     public Rectangle2D getStringBounds( String str,
 552                                         int beginIndex, int limit,
 553                                         Graphics context) {
 554         return font.getStringBounds(str, beginIndex, limit,
 555                                         myFRC(context));
 556     }
 557 
 558    /**
 559      * Returns the bounds of the specified array of characters
 560      * in the specified {@code Graphics} context.
 561      * The bounds is used to layout the {@code String}
 562      * created with the specified array of characters,
 563      * {@code beginIndex} and {@code limit}.
 564      * <p>Note: The returned bounds is in baseline-relative coordinates
 565      * (see {@link java.awt.FontMetrics class notes}).
 566      * @param chars an array of characters
 567      * @param beginIndex the initial offset of the array of
 568      * characters
 569      * @param limit the end offset of the array of characters
 570      * @param context the specified {@code Graphics} context
 571      * @return a {@code Rectangle2D} that is the bounding box of the
 572      * specified character array in the specified
 573      * {@code Graphics} context.
 574      * @see java.awt.Font#getStringBounds(char[], int, int, FontRenderContext)
 575      */
 576     public Rectangle2D getStringBounds( char [] chars,
 577                                         int beginIndex, int limit,
 578                                         Graphics context) {
 579         return font.getStringBounds(chars, beginIndex, limit,
 580                                         myFRC(context));
 581     }
 582 
 583    /**
 584      * Returns the bounds of the characters indexed in the specified
 585      * {@code CharacterIterator} in the
 586      * specified {@code Graphics} context.
 587      * <p>Note: The returned bounds is in baseline-relative coordinates
 588      * (see {@link java.awt.FontMetrics class notes}).
 589      * @param ci the specified {@code CharacterIterator}
 590      * @param beginIndex the initial offset in {@code ci}
 591      * @param limit the end index of {@code ci}
 592      * @param context the specified {@code Graphics} context
 593      * @return a {@code Rectangle2D} that is the bounding box of the
 594      * characters indexed in the specified {@code CharacterIterator}
 595      * in the specified {@code Graphics} context.
 596      * @see java.awt.Font#getStringBounds(CharacterIterator, int, int, FontRenderContext)
 597      */
 598     public Rectangle2D getStringBounds(CharacterIterator ci,
 599                                         int beginIndex, int limit,
 600                                         Graphics context) {
 601         return font.getStringBounds(ci, beginIndex, limit,
 602                                         myFRC(context));
 603     }
 604 
 605     /**
 606      * Returns the bounds for the character with the maximum bounds
 607      * in the specified {@code Graphics} context.
 608      * @param context the specified {@code Graphics} context
 609      * @return a {@code Rectangle2D} that is the
 610      * bounding box for the character with the maximum bounds.
 611      * @see java.awt.Font#getMaxCharBounds(FontRenderContext)
 612      */
 613     public Rectangle2D getMaxCharBounds(Graphics context) {
 614         return font.getMaxCharBounds(myFRC(context));
 615     }
 616 
 617     private FontRenderContext myFRC(Graphics context) {
 618         if (context instanceof Graphics2D) {
 619             return ((Graphics2D)context).getFontRenderContext();
 620         }
 621         return DEFAULT_FRC;
 622     }
 623 
 624 
 625     /**
 626      * Returns a representation of this {@code FontMetrics}
 627      * object's values as a {@code String}.
 628      * @return    a {@code String} representation of this
 629      * {@code FontMetrics} object.
 630      */
 631     public String toString() {
 632         return getClass().getName() +
 633             "[font=" + getFont() +
 634             "ascent=" + getAscent() +
 635             ", descent=" + getDescent() +
 636             ", height=" + getHeight() + "]";
 637     }
 638 
 639     /**
 640      * Initialize JNI field and method IDs
 641      */
 642     private static native void initIDs();
 643 }