JDK-6526129 : Incorrect placement of Strings subject to certain AffineTransforms
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-02-16
  • Updated: 2010-04-04
  • Resolved: 2007-02-16
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
OS Name	Microsoft Windows XP Home Edition
Version	5.1.2600 Service Pack 2 Build 2600


EXTRA RELEVANT SYSTEM CONFIGURATION :
Installed JDK/JRE with Netbeans 5.5. Running as standalone.

A DESCRIPTION OF THE PROBLEM :
When drawing a String and the Graphic's AffineTransform represented by entries m00, m10, m01, m11, m02, m12 is such that m01<0 and m11<0, the String is incorrectly rendered.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the SSCCE provided below.

Or: set the Graphic's transform by

 g2.transform(new AffineTransform(1.0, 0.0, -0.5, -1.0, 0.0, 0.0));

 or to to any AffineTransform, where the 2nd column has all entries negative, and draw a String by:

 g2.drawString("hello", x, y);

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
When running the SSCCE I was expecting that the String would remain within the containing rectangle and not "jump" out for certain values of the AffineTransform.
ACTUAL -
Running the code will show exactly what I saw.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
No error messages.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
<code>
/*
 * TransformedStringBugDemo.java
 *
 * Created on February 13, 2007, 7:23 AM
 */


import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JPanel;
import static java.lang.Math.*;
import javax.swing.Timer;

/**
 *
 * @author  James Vagabond
 *
 * This class is written to show that there is a bug in java.swing. It draws
 * a string inside a rectangle subject to various affine
 * transformations. The affine transformations should keep the text within the
 * rectangle, but for some affine transformations, the text makes a 180 degree
 * rotation out of the rectangle. This occurs when m01 and m11 components are
 * both negative, where m01 and m11 are defined as in the javadoc of
 * AffineTransform.
 */
public class TransformedStringBugDemo extends javax.swing.JFrame {

    /**
     * TransformedStringBugDemo Constructor;
     */
    public TransformedStringBugDemo() {
        initComponents();
        Graphics2D g2 = (Graphics2D) panel.getGraphics();

// Calculate the size of text and set dimension to allow for 4 pts around text
        g2.setFont(font);
        TextLayout layout = new TextLayout(text, g2.getFont(), g2.getFontRenderContext());
        Rectangle2D r = layout.getBounds();
        rectW = (int) (r.getWidth() + 8.5);
        rectH = (int) (r.getHeight() + 8.5);
    }
    
    private String text = "Hello, World!";
    private int rectW;
    private int rectH;
    private AffineTransform at = new AffineTransform();
    private double theta;
    private double delta = PI/100;
    private Font font = new Font("Helvetica", Font.BOLD, 24);
    private JPanel panel = new JPanel() {
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            int h = getHeight();
            int w = getWidth();
            
//Clear the panel:
            g2.setColor(Color.WHITE);
            g2.fillRect(0,0,w,h);
            
            g2.setColor(Color.BLACK);
            g2.setFont(font);
            
//Save the user space transform:
            AffineTransform savedAt = g2.getTransform();
            
//Move the origin to the center of the panel:
            g2.translate(w/2, h/2);
            
//Draw coordinate axes:
            g2.drawLine(-w/2, 0, w/2, 0);
            g2.drawLine(0, -h/2, 0, h/2);
            
//Change the affine transformation of the graphics object and draw a
//text string inside a rectangle.
            g2.transform(at);
            drawBoxedText(g2); // Draws text *inside* a box.

//Reset the transform:
            g2.setTransform(savedAt);
        }
    };
    
    private Button startButton = new Button("Start"); //Used to start and stop animation
    
    /**
     * Updates the affine transformation. The transformation is defined by
     * keeping the e0 unchanged and rotating e1 by theta.
     */
    private Action  updateTransformAction = new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            at.setTransform(1.0, 0.0, -sin(theta), cos(theta), 0.0, 0.0);
            panel.repaint();
            theta += delta;
        }
    };
    
    private Timer t = new Timer(50, updateTransformAction);
                                                            
    
    private boolean running = false;
    
    
    /** This method is called from within the constructor to
     * initialize the form.
     */
    private void initComponents() {
        
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new java.awt.Dimension(400, 400));
        pack();
        getContentPane().add(panel, java.awt.BorderLayout.CENTER);
        getContentPane().add(startButton, java.awt.BorderLayout.SOUTH);
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!running) {
                    t.start();
                    running = true;
                    startButton.setLabel("Stop");
                } else {
                    t.stop();
                    running = false;
                    startButton.setLabel("Start");
                }
            }
        });
    }
/**
 * Draws text centered inside a rectangle.
 * Note: Although the rectangle and the text may be subject to an
 * affine transformation, the affine transformation should keep the text
 * within the rectangle/parallelogramme.
 *
 */
    private void drawBoxedText(Graphics2D g2) {
//Draw a rectangle that is 8 pts wider and taller than text with lower left
//corner at the origin.
        g2.drawRect(0, -rectH, rectW, rectH );
        
//Draw text centered within the rectangle.
        g2.drawString(text, 4, -4);
    }
    
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TransformedStringBugDemo().setVisible(true);
            }
        });
    }
    
}

</code>
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
None known.

Comments
EVALUATION Duplicate of 6479365: Combining negative scale and negative shear in Font Transform produced incorrect results in JDK 6 This is fixed in JDK6 update 1
16-02-2007