Graphics2D.drawString() fails with Font derived from rotated + scaled AffineTransform
Daniel Gredler
djgredler at gmail.com
Mon Sep 9 23:56:52 UTC 2024
Hi all,
I've done a little more digging, and there is indeed a deeper bug in
TextLayout.getOutline(AffineTransform), where the transformation is applied
too early (before the layout path applies its mapping).
There are two uses of TextLayout.getOutline(AffineTransform): the first
one, triggered via a simple Graphics2D.drawString( ) was the one I ran
into; the second one requires the use of a transformed font with a
PSPrinterJob. Both are broken, so it doesn't really make sense to work
around the TextLayout issue for the first scenario, but leave the second
scenario broken.
The deeper fix, including two test classes verifying that both scenarios
were broken and now work correctly, is available on GitHub [1]. I plan to
submit a PR as soon as I have a final bug ID from my web bug submission.
Two points I'd like some feedback on:
1. I've changed the signature of method
TextLine.getOutline(AffineTransform), to just TextLine.getOutline( ); I'm
assuming this is OK since TextLine is a package-private class?
2. I've added a fast path in TextLayout.getOutline(AffineTransform) to
transform the shape in place if it is a GeneralPath (it should usually be,
and avoids an extra Shape copy vs. the current code); does this look OK? Or
should the code be kept completely generic and a copy always made? I had a
look at just changing the variable type from Shape to GeneralPath, but the
change started to cascade into a few other classes and I pulled the plug.
Take care,
Daniel
[1]
https://github.com/openjdk/jdk/compare/master...gredler:jdk:draw-string-bug-2
On Thu, Sep 5, 2024 at 8:30 PM Daniel Gredler <djgredler at gmail.com> wrote:
> Hi all,
>
> I've run into a bug [1] in the drawing of strings via
> Graphics2D.drawString(), when used with a Font derived from a rotated +
> scaled AffineTransform. If the AffineTransform scaling is small, the text
> draws correctly. But if the scale is too large, the text does not draw. [3]
>
> It looks like it's an effect of the OutlineTextRenderer.THRESHHOLD; text
> larger than this threshold is sent to the OutlineTextRenderer and fails to
> draw. The fix [2] seems to be to apply the position translation
> transformation *after* the text outline shape is created, rather than
> passing it into TextLayout.getOutline(). However, I do not know if this is
> the correct fix, or if it is just a workaround to a deeper issue in
> TextLayout.getOutline(), which in theory might need to wait to apply the
> provided translation until after the layout path has had a chance to map to
> user space.
>
> Can someone familiar with this code comment on whether the proposed fix is
> the correct fix, or whether deeper surgery is needed in
> TextLayout.getOutline()?
>
> My other small worry with the current fix [2] is that it creates an extra
> copy of the Shape object, so it's going to allocate a bit more memory than
> the current implementation. Not sure if there's a better way to update the
> Shape in-place.
>
> Take care,
>
> Daniel
>
> ---
>
> [1] Oracle internal review ID 9077538, no public bug ID yet
> [2]
> https://github.com/openjdk/jdk/compare/master...gredler:jdk:draw-string-bug
> [3]
> import java.awt.Color;
> import java.awt.Font;
> import java.awt.Graphics2D;
> import java.awt.geom.AffineTransform;
> import java.awt.image.BufferedImage;
> import java.io.File;
>
> import javax.imageio.ImageIO;
>
> /**
> * <p>The "TEST 2" text does not draw. NOTE: Reducing the AffineTransform
> scale
> * from 12 to 10 seems to allow it to draw?!?
> *
> * <p>Oracle internal review ID : 9077538
> */
> public class DrawStringTest {
>
> public static void main(String[] args) throws Exception {
>
> AffineTransform at = AffineTransform.getRotateInstance(3 * Math.PI
> / 2);
> at.scale(12, 12);
>
> Font font1 = new Font("SansSerif", Font.PLAIN, 10);
> Font font2 = font1.deriveFont(at);
>
> BufferedImage image = new BufferedImage(500, 500,
> BufferedImage.TYPE_BYTE_GRAY);
> Graphics2D g2d = image.createGraphics();
> g2d.setColor(Color.WHITE);
> g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
> g2d.setColor(Color.BLACK);
> g2d.setFont(font1);
> g2d.drawString("TEST 1", 200, 400); // draws text
> g2d.setFont(font2);
> g2d.drawString("TEST 2", 200, 400); // does not draw text
> g2d.dispose();
>
> ImageIO.write(image, "png", new File("test.png"));
> }
>
> }
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/client-libs-dev/attachments/20240910/5c97f74f/attachment-0001.htm>
More information about the client-libs-dev
mailing list