Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6644301
Votes 0
Synopsis lightweight components can repaint outside request bounds
Category java:classes_awt
Reported Against
Release Fixed 7(b29)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs
Submit Date 20-DEC-2007
Description
FULL PRODUCT VERSION :
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode, sharing)



ADDITIONAL OS VERSION INFORMATION :
 customer  Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Calling repaint on a lightweight component with negative x or y coordinate and with width and height that do not exceed the the component dimensions will forward the call to the parent container with the negative coordinate(s) set to zero but without reducing the corresponding width(s). The result is that the parent container will repaint an area that falls outside the requested bounds of the repaint (although not outside the bounds of the lightweight component). This is contrary to the specification and can cause unnecessary flicker.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
if lwc is a lightweight component, call lwc.repaint(-100, 0, getWidth(), getHeight());

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The rightmost 100 pixels of lwc should be unaffected by this call, since it is outside the requested repaint rectangle.
ACTUAL -
The call will cause the entire component to be repainted.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;

/**
 * Demonstrates a repaint bug in lightweight components. When run,
 * clicking on the "red" button will cause the red square to repaint
 * entirely. Click it quickly and repeatedly on a system that is slow enough,
 * you can see the resulting flicker extend halfway across the blue
 * square where the squares overlap. (I can see a bit of flicker on my
 * Windows box with a 1.8GHz AMD Athlon 64 processor.)
 *
 * According to the documentation, painting as a result of a call to repaint
 * should be confined to the bounds of the requested rectangle.
 */
public class Foo extends Frame {
  public static void main(String [] args) {
    Foo f = new Foo();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosed(WindowEvent e) { System.exit(0); }
      public void windowClosing(WindowEvent e) { e.getWindow().dispose(); }
    });
    f.pack();
    f.setVisible(true);
  }

  public Foo() {
    setLayout(null);
    a = new W();
    b = new W();
    a.setBackground(Color.red);
    b.setBackground(Color.blue);
    btnA = new Button("red");
    btnA.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        a.repaint(-100, 0 ,a.getWidth(), a.getHeight());
      }
    });
    btnB = new Button("blue");
    btnB.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        b.repaint();
      }
    });
    add(a);
    add(b);
    add(btnA);
    add(btnB);
    setComponentZOrder(a, 1);
    setComponentZOrder(b, 0);
  }

  public void doLayout() {
    a.setBounds(50, 50, 200, 200);
    b.setBounds(150, 150, 200, 200);
    Dimension btnAPref = btnA.getPreferredSize();
    Dimension btnBPref = btnB.getPreferredSize();
    int left = (getWidth() - btnAPref.width - btnBPref.width) / 2 - 10;
    int top = getHeight() - btnAPref.height - 10;
    btnA.setBounds(left, top, btnAPref.width, btnAPref.height);
    btnB.setBounds(left + btnAPref.width + 20, top, btnBPref.width, btnBPref.height);
  }

  public Dimension getPreferredSize() { return new Dimension(400, 500); }

  private W a;
  private W b;
  private Button btnA;
  private Button btnB;

  private static class W extends Component {
     public void paint(Graphics g) {
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());
     }
  }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Do the necessary argument clamping in the code that calls repaint:

if (left < 0) {
  width += left;
  left = 0;
}
if (top < 0) {
  height += top;
  top = 0;
}
lwc.repaint(left, top, width, height);
Posted Date : 2007-12-20 10:10:03.0
Work Around
N/A
Evaluation
Here is the code in Component.repaint() method:

    if (parent != null) {
        int px = this.x + ((x < 0) ? 0 : x);
        int py = this.y + ((y < 0) ? 0 : y);
        int pwidth = (width > this.width) ? this.width : width;
        int pheight = (height > this.height) ? this.height : height;
        parent.repaint(tm, px, py, pwidth, pheight);
    } else {
        ...
    }
    
If x is negative, the rectangle to be painted just is just shifted right. Instead, its width should be also corrected.
Posted Date : 2007-12-28 13:17:41.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang