-
Enhancement
-
Resolution: Fixed
-
P1
-
1.2.0
-
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.
- duplicates
-
JDK-4086564 In jdk1.2Beta1, the I-bean caret , in JTextField, is located at wrong position.
-
- Closed
-
-
JDK-4111670 Selection highlight doesn't match text in JEditorPane
-
- Closed
-
-
JDK-4133491 JTextField cursor ...
-
- Closed
-
- relates to
-
JDK-4086514 TextLayout.getCaretInfo(TextHit(0))[0] returning Advance
-
- Closed
-
-
JDK-4087671 TextLayout.getCaretInfo(hit) xAdvances on TrueType fonts are way off
-
- Closed
-
-
JDK-4116576 Swing text is not drawn correctly with JDK-1.2beta3-J on Solaris and winNT
-
- Closed
-
-
JDK-4077865 Relative position of characters within a string varies with position of text
-
- Closed
-
-
JDK-4102059 FontMetrics.stringWidth & Graphics.drawString do not agree on length
-
- Closed
-
-
JDK-4128234 Cursor misplaced after DBCS char that uses odd size font
-
- Closed
-
-
JDK-4104022 Bounds of a shape generated from the outline of a GlyphSet not always correct
-
- Closed
-
-
JDK-4026923 missing functionality for FontMetrics class
-
- Closed
-
-
JDK-4086824 TextLayout.getBlackBoxBounds() values questionable
-
- Closed
-
-
JDK-4087651 TextLayout.getCaretInfo(hit) not returning correct xAdvances
-
- Closed
-
-
JDK-4116940 Highlighting Swing text backwards corrupts the text as it is highlighted
-
- Closed
-
-
JDK-4109376 FontMetrics inaccurate, core dumps printing unicode
-
- Closed
-