java2d-interest  

Re: [JAVA2D] 1.4 regression bug

Doug Felt
Mon, 04 Feb 2002 16:07:15 -0800

First, let me apologize for the inadequate documentation on
FontRenderContext (FRC) and its role in text layout and rendering.
Unfortunately, the documentation for FRC does not define the behavior when
the FRC does not match the state of the Graphics.

The JDK 1.3. documentation for the FRC class does warn about unpredictable
results when using an FRC not obtained from a Graphics, and in fact, in JDK
1.3.1 and prior, Graphics2D.getFontRenderContext always returns an FRC with
an identity transform, regardless of what Graphics it is or what transforms
have been applied to it.  Behavior using FRCs not obtained from a
Graphics2D is unspecified.  The behavior you saw in JDK 1.3 was actually a
bug.

Let me briefly (?) explain how the FRC is used.

Layout of text is based on the FRC in effect when layout is
performed, but the actual rendering is based on the current graphics state.
Typically these are the same (for example, they're always the same with
Graphics.drawString) but they don't have to be.  You might, for example,
want to layout text based on printer resolution, but display it at screen
resolution.  Or you might layout text based on a standard horizontal line,
but use a transform to zoom or rotate the display.  The key point is, the
metrics of the text (overall advance, glyph positions, logical and visual
bounds) are constant, and are based on the FRC used to construct the
layout.  The actual rendered appearance of the glyphs, though, depends on
the graphics state at the time of rendering.

This is what allows TextLayout to compute metric information for the text
independently of the graphics transform used to render the layout.
TextLayout metrics are in 'user space,' which is independent of the
transform applied to the graphics.  So, for example, you can use the text
metrics to compute a rectangle to frame the text, and then draw both text
and frame without adjustment under different graphics transforms, and get
the same alignment of the text and the frame. You can layout text based on
one graphics state (for instance, one that coresponds to the printer you
plan on printing to) but display it in another graphics state (for
instance, the screen) while keeping the same overall metrics (advance,
ascent/descent, glyph and caret positions).  You can 'zoom in' on the text
on the screen and it won't change the positions or metrics, but it will
attempt to give you the best image, because the individual glyphs rendered
to the screen are hinted based on the current graphics state.

The FRC represents the information about the graphics device that impact
text metrics, such as advance vector and bounding box, and in particular,
the AffineTransform of the FRC represents the resolution and orientation of
the pixel grid to which glyphs are hinted.  You can see this very clearly
when the FractionalMetrics text rendering hint is off, and the FRC
transform is small, say [0.02 0 0 0.02].  This FRC transform is saying that
pixels are very big-- the identity transform corresponds to 72 pixels per
inch, so this transform corresponds to a raster of about one and a half
pixels per inch.  When fractional metrics is off, advances are rounded to
pixel boundaries, and with such large pixels you can really see the effect
on glyph placement.  As another example, a rotated FRC transform means that
the pixel raster is rotated, and generally when the raster is rotated,
glyph hinting not performed (since then the hinting rules in the font don't
work correctly).  Hinting is what gives you balanced stem weights and
spacing (for example, in the letter 'm') and it can affect the glyph
advance with some rasterizers.

If you render a TextLayout using the same FRC in the graphics, you will see
results that exactly match the metrics returned from TextLayout.  When you
render text, we use the glyph positions and advances computed under the
FRC, but rehint and render the individual glyphs based on the current
graphics transform and rendering hints.  (Anti-aliasing should work this
way too, but some rasterizers/fonts can't support AA rendering, and in our
current implementation if we use a different AA flag to render the pipeline
can end up using different fonts and get different actual glyphs. This is a
problem we plan to remedy in the future, but didn't manage to fix for JDK
1.4).  Anyway, since we recompute the glyph raster based on the rendering
transform, the glyph still looks good under the rendering transform.  In
the example above that had a very coarse raster in the FRC, the glyph
position was determined based on the glyph advances under the FRC raster,
but since the rendered glyphs are based on the current screen raster, the
glyphs are still legible-- otherwise each glyph would just be a large blob.

The supported way to get the effect you described is to apply a transform
to the graphics before rendering the TextLayout.  You can wrap each
TextLayout in another object that applies the transform (and perhaps other
things like color) to the graphics before delegating the actual rendering
to the TextLayout.  Or you can just set up the graphics before rendering.

Once again, let me apologize for the poor documentation.  The documentation
should have described how the rendering system uses the
FRC in much more detail.

Doug

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA2D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".