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

[macosx] jdk8, jdk7u60 Regression in Graphics2D drawing of derived Fonts

    XMLWordPrintable

Details

    • 2d
    • b45
    • x86
    • os_x

    Backports

      Description

        FULL PRODUCT VERSION :
        java version "1.8.0_25"
        Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
        Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Mac OSX 10.9.5

        A DESCRIPTION OF THE PROBLEM :
        Rotating text is broken when using Font#deriveFont to draw String.
        See sample.
        It seems regression appeared after Java 7 u40.
        It affects currently Apache JMeter project, see:
        https://issues.apache.org/bugzilla/show_bug.cgi?id=57221

        Thanks for help

        ADDITIONAL REGRESSION INFORMATION:
        java version "1.8.0_25"
        Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
        Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run on Java 7u40, you get a Frame with correclty drawn text
        Run it with Java8 or Java7u71, you get a strange rotation of characters

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Correct rotation of text
        ACTUAL -
        Strange rotation of text which does not comply with previous behaviour

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        No error message

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------

        import java.awt.Color;
        import java.awt.Dimension;
        import java.awt.Font;
        import java.awt.Graphics;
        import java.awt.Graphics2D;
        import java.awt.RenderingHints;
        import java.awt.font.FontRenderContext;
        import java.awt.font.LineMetrics;
        import java.awt.geom.AffineTransform;
        import java.awt.geom.GeneralPath;
        import java.awt.geom.Rectangle2D;

        import javax.swing.JFrame;
        import javax.swing.JPanel;

        public class Test extends JPanel {
            Rectangle2D.Float rect = new Rectangle2D.Float(200, 200, 220, 35);
            // float theta = 1.1748778437843f;
            double theta = Math.PI / 6;

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g;
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                        RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                        RenderingHints.VALUE_STROKE_PURE);
                g2.setPaint(Color.blue);
                Font font = g2.getFont().deriveFont(18f);
                g2.setFont(font);
                FontRenderContext frc = g2.getFontRenderContext();
                String s = "This text should be rotated";
                float width = (float) font.getStringBounds(s, frc).getWidth();
                LineMetrics lm = font.getLineMetrics(s, frc);
                float height = lm.getAscent() + lm.getDescent();
                // Scale text into rect.
                float xScale = rect.width / width;
                float yScale = rect.height / height;
                float scale = (xScale > yScale) ? yScale : xScale;
                // Locate string origin.
                double x = rect.x;
                double y = rect.y + (rect.height + scale * height) / 2 - scale
                        * lm.getDescent();
                AffineTransform at = AffineTransform.getTranslateInstance(x, y);
                at.scale(scale, scale);
                AffineTransform rotator = new AffineTransform();
                rotator.rotate(theta, rect.getCenterX(), rect.getCenterY());
                GeneralPath rect2 = new GeneralPath(
                        rotator.createTransformedShape(rect));
                // Draw with no rotation.
                g2.draw(rect);
                g2.setPaint(Color.red);
                g2.setFont(font.deriveFont(at));
                g2.drawString(s, 0, 0);
                // Rotate once.
                g2.setPaint(Color.blue);
                g2.draw(rect2);
                rotator.concatenate(at);
                g2.setFont(font.deriveFont(rotator));
                g2.setPaint(Color.red);
                g2.drawString(s, 0, 0);
                // Rotate again.
                rotator.setToIdentity();
                rotator.rotate(2 * theta, rect.getCenterX(), rect.getCenterY());
                rect2 = new GeneralPath(rotator.createTransformedShape(rect));
                g2.setPaint(Color.blue);
                g2.draw(rect2);
                rotator.concatenate(at);
                g2.setFont(font.deriveFont(rotator));
                g2.setPaint(Color.red);
                g2.drawString(s, 0, 0);
                // Check scaled string bounds.
                // this was handled by the fractional metrics rendering hint
            }

            public static void main(String[] args) {
                Test test = new Test();
                test.setPreferredSize(new Dimension(800, 600));
                JFrame f = new JFrame();
                f.getContentPane().add(test);
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setVisible(true);
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        None found

        Attachments

          Issue Links

            Activity

              People

                serb Sergey Bylokhov
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: