Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4130434

The Measurement of Text

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P1 P1
    • 1.2.0
    • 1.2.0
    • client-libs
    • 2d
    • 1.2beta4
    • generic, x86, sparc
    • generic, solaris_2.5, solaris_2.5.1, solaris_2.6, windows_95, windows_nt
    • Not verified


      paul.charlton@eng 1998-04-18
      ===============================================================================
      The Measurement of Text.

      The Java2D font architecture has added some advanced typographic features such
      as application control over AntiAliasing and the use of Fractional Metrics.

      As of Beta3, not all design issues had been uncovered and put through trial,
      Beta2 and Beta3 developers have already found a number of inconsistencies
      in the placement of character and Glyphs on a page of text. This Request
      for Enhancement addresses the comprehensive needs of developers desiring
      presice placement of glyphs, and defines an implementation which organizes
      the appropriate change into logical groupings which facilite quicker
      comprehension of advanced font rendering and its implications.

      ===============================================================================
      Problem 1:

      Modern fonts such as TrueType support features such as algorithmic hinting,
      which can typically make characters larger when they are displayed on
      low resolution devices, in order to keep a character such as an "o" from
      becoming a blob with no open center. Rendering of fonts is device dependent
      with respect to scale of user coordinates to pixels.

      The state needed to determine the placement of all of the pixels in a glyph
      consists of (1) scale, (2) antialiasing, and (3) fractional metrics. Until
      one has this state in hand, any measurements taken from a font or a glyph
      are approximations which may yield inaccurate and/or surprising results
      when used to layout text.

      To provide a solution which addresses the technical areas described above,
      we have introduced a new class "FontRenderContext" which contains sufficient
      state for the accurate measurement of text rendering. We have also thoroughly
      researched all areas in which a user of the API in the "java" package can
      attempt to perform measurement of text, and have modified the public
      implementation in such as way as to make a programmer aware of the issues
      involved in the measurement of text. All advanced measurement which has been
      introduced since JDK1.1 will be made inacessible to a programmer until they
      have obtained an applicable FontRenderContext or sufficient state (such as
      a target Graphics.)

      Additionally, if a program attempts to use JDK 1.1 compatible integer-only
      FontMetrics methods subsequent to setting ANTIALIAS or FRACTIONALMETRICS modes,
      an exception of type "AWTException" will be thown with a message indicating
      improper use of the font rendering subsystem. Special care has been take to
      assure that legacy JDK applications will not see this exception.

      This change has code implications of the following nature:

      ===================================
      Original code:

      Component c = foo;
      int width = c.getFontMetrics(font).stringWidth("measuring");

      ===================================
      New code:

      Component c= foo;
      Graphics gContext = c.getGraphics();
      float width = c.getFontMetrics(font).getStringBounds("measuring", gContext).getWidth();

      ===============================================================================
      Problem 2:

      International Unicode fonts tend to contain representations of characters from
      many different script systems. The measurement of text for the placement of
      a sequence of lines depends on the particular script system(s) used for the
      text within that line. In particular, metrics such as: ascent, descent, leading,
      height, and baseline offset (LineMetrics) are dependent on the script system.

      In JDK 1.1, no means was provided to distinguish between script systems within
      a single font, and erroneous layout is made when text made use of characters
      from a non-default script system within a Font. As of Beta3, JDK1.2 did not
      support a distinction between line metrics for characters from different
      script systems.

      This problem has been addressed by the introduction of a new class
      java.awt.font.LineMetrics which can be instantiated through factories on
      both java.awt.Font and java.awt.FontMetrics.


      Areas of further consideration:
      1) create a new exception type which is specific to text measurements.

      Shorthand summary of API changes:
      ===============================================================================

      Related Font Measuring bugs:
      4086564, 4087651, 4116576, 4087671, 4086514, 4086824,
      4077865, 4116940, 4102059, 4102270, 4109376, 4128234,
      4026923, 4104022

      class java.awt.Font.java

      changed:
      M1 <old> public java.awt.geom.Rectangle2D getMaxBounds2D();
      M1 <new> public java.awt.geom.Rectangle2D getMaxCharBounds(java.awt.font.FontRenderContext);

      added:
      M1 <new> protected float pointSize;

      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(java.lang.String, java.awt.font.FontRenderContext);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(java.lang.String, int, int, java.awt.font.FontRenderContext);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(java.text.CharacterIterator, int, int, java.awt.font.FontRenderContext);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(char[], int, int, java.awt.font.FontRenderContext);

      M1 <new> public boolean hasUniformLineMetrics();
      M1 <new> public int retrieveLineMetrics(java.lang.String, java.awt.font.FontRenderContext, java.awt.Font.LineMetrics);
      M1 <new> public int retrieveLineMetrics(java.lang.String, int, int, java.awt.font.FontRenderContext, java.awt.Font.LineMetrics);
      M1 <new> public int retrieveLineMetrics(java.text.CharacterIterator, int, int, java.awt.font.FontRenderContext, java.awt.Font.LineMetrics);
      M1 <new> public int retrieveLineMetrics(char[], int, int, java.awt.font.FontRenderContext, java.awt.Font.LineMetrics);

      removed:
      M1 <old> public float getAdvance(char);
      M1 <old> public float getAdvance(char[]);

      M1 <old> public java.awt.font.GlyphJustificationInfo getGlyphJustificationInfo(int);
      M1 <old> public java.awt.font.GlyphMetrics getGlyphMetrics(int);
      M1 <old> public float getMetrics(java.awt.font.GlyphSet, java.awt.geom.AffineTransform)[];
      N1 <old> public java.text.AttributeSet getRequestedAttributes();

      M1 <old> public float getAscent();
      M1 <old> public float getDescent();
      M1 <old> public float getLeading();
      M1 <old> public float getMaxAdvance();
      M1 <old> public int sameBaselineUpTo(java.text.CharacterIterator);
      M1 <old> public int sameBaselineUpTo(char[], int, int);
      M1 <old> public boolean isUniformBaseline();
      M1 <old> public boolean isVerticalBaseline();
      M1 <old> public float getBaselineOffset(byte);
      M1 <old> public float getBaselineOffsetsFor(char)[];
      M1 <old> public float getStrikethroughOffsetFor(char);
      M1 <old> public float getStrikethroughThicknessFor(char);
      M1 <old> public float getUnderlineOffsetFor(char);
      M1 <old> public float getUnderlineThicknessFor(char);

      added:
      M1 <new>public final class java.awt.font.LineMetrics extends java.lang.Object {
      M1 <new> public final float getAscent();
      M1 <new> public final int getBaselineIndex();
      M1 <new> public final float getBaselineOffsets()[];
      M1 <new> public final float getDescent();
      M1 <new> public final float getHeight();
      M1 <new> public final float getLeading();
      M1 <new> public final float getStrikethroughOffset();
      M1 <new> public final float getStrikethroughThickness();
      M1 <new> public final float getUnderlineOffset();
      M1 <new> public final float getUnderlineThickness();

      M1 <new> class java.awt.font.FontRenderContext.java added:
      M1 <new> public class FontRenderContext extends java.lang.Object
      M1 <new> {
      M1 <new> protected java.awt.font.FontRenderContext();
      M1 <new> public java.awt.font.FontRenderContext(java.awt.geom.AffineTransform,boolean,boolean);
      M1 <new> public java.awt.geom.AffineTransform getTransform();
      M1 <new> public boolean isAntiAliased();
      M1 <new> public boolean usesFractionalMetrics();
      M1 <new> }

      ============================================================================
      class java.awt.FontMetrics

      added:
      M1 <new> public Rectangle2D getMaxCharBounds(java.awt.Graphics);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(java.lang.String, java.awt.Graphics);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(java.lang.String, int, int, java.awt.Graphics);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(java.text.CharacterIterator, int, int, java.awt.Graphics);
      M1 <new> public java.awt.geom.Rectangle2D getStringBounds(char[], int, int, java.awt.Graphics);

      M1 <new> public boolean hasUniformLineMetrics();
      M1 <new> public int retrieveLineMetrics(java.lang.String, java.awt.Graphics, java.awt.Font.LineMetrics);
      M1 <new> public int retrieveLineMetrics(java.lang.String, int, int, java.awt.Graphics, java.awt.Font.LineMetrics);
      M1 <new> public int retrieveLineMetrics(java.text.CharacterIterator, int, int, java.awt.Graphics, java.awt.Font.LineMetrics);
      M1 <new> public int retrieveLineMetrics(char[], int, int, java.awt.Graphics, java.awt.Font.LineMetrics);

      ============================================================================
      class java.awt.Graphics2D.java

      added:

      M1 <new> public abstract java.awt.font.FontRenderContext getFontRenderContext();

      => affects public child class java.awt.print.PeekGraphics
      => affects public child class java.awt.print.ProxyGraphics2D

      ============================================================================
      class java.awt.font.TextLayout

      changed:
      M1 <old> public TextLayout(java.lang.String string, java.awt.Font);
      M1 <new> public TextLayout(java.lang.String string, java.awt.Font, java.awt.font.FontRenderContext);

      M1 <old> public TextLayout(java.lang.String, java.util.Map);
      M1 <new> public TextLayout(java.lang.String, java.util.Map, java.awt.font.FontRenderContext);

      M1 <old> public TextLayout(java.text.AttributedCharacterIterator);
      M1 <new> public TextLayout(java.text.AttributedCharacterIterator, java.awt.font.FontRenderContext);

      ============================================================================
      class java.awt.font.LineBreakMeasurer

      changed:
      M1 <old> public LineBreakMeasurer(java.text.AttributedCharacterIterator);
      M1 <new> public LineBreakMeasurer(java.text.AttributedCharacterIterator,java.awt.font.FontRenderContext);

      M1 <old> public LineBreakMeasurer(java.text.AttributedCharacterIterator,java.text.BreakIterator);
      M1 <new> public LineBreakMeasurer(java.text.AttributedCharacterIterator,java.text.BreakIterator,java.awt.font.FontRenderContext);

      paul.charlton@eng 1998-04-23
      Response to address questions from review process:

      rename 4 methods in java.awt.Font
      from retrieveLineMetrics to "computeLineMetricsUpTo"
      These calls return the index+1 of the last character processed from the input characters. The processing stops when a character is found which has different LineMetrics from the preceding characters (or at the end of input). These calls fill out a LineMetrics object supplied by the caller.
      They allow a caller to efficiently interate and retrive LineMetrics for a string which has mixed script systems.


      paul.charlton@eng 1998-04-23
      Further iteration ...
      remove retrieveLineMetrics and computeLineMetricsUpTo

      In class java.awt.FontMetrics replace with:
      M1 <new> public LineMetrics getLineMetrics(java.lang.String,java.awt.Graphics);
      M1 <new> public LineMetrics getLineMetrics(java.lang.String, int, int,
                                                                   java.awt.Graphics);
      M1 <new> public LineMetrics getLineMetrics(java.text.CharacterIterator,
                                                                   int, int,
                                                                   java.awt.Graphics);
      M1 <new> public LineMetrics getLineMetrics(char[], int, int,
                                                                   java.awt.Graphics);

      In class java.awt.Font replace with:
      M1 <new> public LineMetrics getLineMetrics(java.lang.String,
                                                  java.awt.font.FontRenderContext);
      M1 <new> public LineMetrics getLineMetrics(java.lang.String, int, int,
                                                  java.awt.font.FontRenderContext);
      M1 <new> public LineMetrics getLineMetrics(java.text.CharacterIterator,
                                                  int, int,
                                                  java.awt.font.FontRenderContext);
      M1 <new> public LineMetrics getLineMetrics(char[], int, int,
                                                 java.awt.font.FontRenderContext);

      In class java.awt.font.LineMetrics:
      added
      M1 <new> public final int getNumChars(); // number of contiguous chars from input which correspond to this LineMetrics object.

            pcharltosunw Paul Charlton (Inactive)
            pcharltosunw Paul Charlton (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: