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

Incorrect placement of Strings subject to certain AffineTransforms

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 6
    • client-libs
    • 2d
    • x86
    • windows_xp

      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.

            Unassigned Unassigned
            ryeung Roger Yeung (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: