JDK-4836162 : Selection and Caret are drawn incorrectly when JTextField is Scaled
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2003-03-21
  • Updated: 2007-03-06
Related Reports
Relates :  
Description

Name: jk109818			Date: 03/21/2003


FULL PRODUCT VERSION :
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Selection and caret are drawn incorrectly when JTextfield
is painted with Graphics2D that has a scale other than 1.

For example, if you scale a Graphics2D object:

Graphics2D g2d = (Graphics2D) g;
AffineTransform at = g2d.getTransform();
at.scale(10, 10);
g2d.setTransform(at);

and then paint a JTextField with that Graphics2D object,
the selection and caret are off by a few pixels.

See & run attached source code.

JDK 1.2.x and JDK 1.3.x had also a problem with JTextField
being painted on a Graphics2D that was translated by non-
integers. This problem seems to be fixed with JDK 1.4.x.
However, the scaling problem still remains.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile attached source code
2. Run.


EXPECTED VERSUS ACTUAL BEHAVIOR :
Observe that the caret and the selection are drawn
incorrectly.


REPRODUCIBILITY :
This bug can be reproduced always.

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

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JPanel;
import java.awt.geom.AffineTransform;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Canvas;
import java.awt.Font;


/**
 * This test case shows that the painting of the JTextField is "off"
 * under certain circumstances (mainly scaling).  It's a very small
 * difference, so this class is designed to show how the issues
 * compound when the scale is increased.
 */
public class MagnifiedTextField extends JFrame
{

  public static void main(String[] argv)
  {
    new MagnifiedTextField();
  }

  public MagnifiedTextField()
  {
    super("Testing magnifying text");
    setSize(900,400);

    delegate_ = new ShuntedJTextField("the text field beckons");
    
    // different fonts show different behaviors,
    // but this one is particularly bad.
    // to see the effect, using the keyboard, highlight
    // the text "field b"
    delegate_.setFont(new Font("Verdana", Font.PLAIN, 9));

    // this sets the selection of the text to somewhere
    // that's a problem
    delegate_.setSelectionStart(8);
    delegate_.setSelectionEnd(14);


    // this paints the text field larger so that
    // the rendering issues are more obvious
    myJPanel_ = new JPanel()
      {
        public void paint(Graphics g)
        {
          if(g instanceof Graphics2D)
          {
            Graphics2D g2d = (Graphics2D) g;
            AffineTransform at = g2d.getTransform();
            at.scale(10, 10);
            g2d.setTransform(at);
            delegate_.myPaint(g2d);
          }
        }

      };

    myJPanel_.add(delegate_);
    setContentPane(myJPanel_);
    setVisible(true);
  }

  public void paint(Graphics g)
  {
    getContentPane().paint(g);
  }


  public class ShuntedJTextField extends JTextField
  {
    public ShuntedJTextField(String str)
    {
      super(str);
    }

    public void repaint(int x, int y, int h, int w)
    {
      // this forces a repaint of the main window
      // instead of this one
      MagnifiedTextField.this.repaint();
    }
    
    public void paint(Graphics g)
    {
      // we want to shunt painting ourselves
    }
    
    public void myPaint(Graphics g)
    {
      super.paint(g);
    }
  }

  JPanel myJPanel_;
  Canvas myCanvas_;
  ShuntedJTextField delegate_;
}

---------- END SOURCE ----------
(Review ID: 179529) 
======================================================================

Comments
EVALUATION Name: anR10225 Date: 07/01/2003 The matter is that we are using FontMetrics in all text related calculations, but we should use FontRenderContext instead to take into account graphic device where text is rendered. The main problem is to get graphic device before the text component is painted to perform layout tasks. ====================================================================== Name: anR10225 Date: 07/04/2003 The graphics context could be obtained from a component as early as component performs layout task. But another problem arises. Text measurements by using TextLayout and FontRenderContext are much more expensive than using FontMetrics though they are more precise. For example Font.getStringBounds(char[], int, int, FontRenderContext) works 30 times longer than FontMetrics.charsWidth(). Measurements performed by GlyphPainter2 are almost 40 times more expensive than GlyphPainter1. ======================================================================
25-09-2004