JDK-6763417 : Graphics.drawImage() operates on the entire JFrame.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6u10
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2008-10-24
  • Updated: 2011-02-16
  • Resolved: 2008-11-08
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
graphic card ATI Radeon 9600/X1050 series

A DESCRIPTION OF THE PROBLEM :
Here is the code of an overriding paint() method of a class that inherits from JFrame.

@Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        BufferedImage img = new
        BufferedImage(getWidth(),27,BufferedImage.TYPE_INT_ARGB);
        Graphics2D buffgr = (Graphics2D) img.getGraphics();
        buffgr.setColor(Color.BLUE);
        buffgr.fill(new Rectangle(0,0,getWidth(),27));
        g2d.drawImage(img, 0, 0,null);
        g2d.setColor(Color.RED);
        g2d.fill(new Rectangle(0,27, getWidth(), getHeight() - 27));
    }
On java version 1.6.0_10  the drawImage function redraws the entire workspace (getWidth(), getHeight()) and not only the image size. It draws the image and on the remaining space draws a background of a very light gray color, causing flickering. This does not appear on java 1.6.0_07, the function with this version draws only on the image size. Furthermore on version 1.6.0_10 cliping does not affect the drawImage() function and more generally using drawImage with version 1.6.0_10 works very more slowly than with version 1.6.0_7

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run the code joined, and resize the window. Flickering appears with version 1.6.0_10 and all works fine with version 1.6.0_7.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package bugreport;

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;


class BJFrame extends JFrame {
    
  @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        BufferedImage img = new      BufferedImage(getWidth(),150,BufferedImage.TYPE_INT_ARGB);
        Graphics2D buffgr = (Graphics2D) img.getGraphics();
        buffgr.setColor(Color.BLUE);
        buffgr.fill(new Rectangle(0,0,getWidth(),150));
        g2d.drawImage(img, 0, 0,null);
        g2d.setColor(Color.RED);
        g2d.fill(new Rectangle(0,150, getWidth(), getHeight() - 150));
    }
       
}
public class Main {

   public static void main(String[] args) {
        BJFrame frame = new BJFrame();
        frame.setBounds(150,150,600,400);
        frame.setVisible(true);
    }

}


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

Release Regression From : 6u7
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

Comments
EVALUATION First, one shouldn't override JFrame.paint(). This screws up Swing's repainting mechanism, since the rendering goes directly to the screen instead of Swing's backbuffer. In particular, it disables the gray rect fix introduced in Java 6 so your expose repainting won't be smooth and gray rect-free. So you really really need to know what you're doing. The cause of the flickering, however, is the mechanism for rendering directly to the screen in the Direct3D pipeline in 6u10. Since it is impossible to render to the screen with Direct3D9 we intercept calls for on-screen rendering and redirect them into a special back-buffer which is then presented (normally once every 100ms). However, since applications don't render _directly_ to the screen because of potential flickering issues but render into an offscreen image which is then copied to the screen, we optimized this scenario and present our special buffer immediately after a drawImage call is completed. This makes applications more responsive since the screen is updated immediately after the drawImage call, and not 100ms later. However, in this test case the draw image call is made before the whole area is filled, so we present whatever is there in the buffer by the time the drawImage call is made - the top is the contents of the image we just rendered (blue), and the bottom which hasn't been rendered yet and filled with background by default. If you only reverse the order - that is, do the fill rect first, and draw image later, you'll eliminate the flickering. I doubt we'll be fixing this since there's an easy work around and the potential benefits of the current implementation are greater than breaking use cases like this. Those rendering directly to the screen without the use of the back-buffer should expect flickering. And for Swing applications it is a very bad idea to render to the screen directly anyway.
08-11-2008

EVALUATION Since gray rect problem was fixed and Swing has true per-window back buffer (#4967886) we don't really support overridden paint() method for a top level windows I believe it was mentioned in tutorials but couldn't find it quickly Anyway, there were no recent changes in Swing painting routine so I checked the given test with the -Dsun.java2d.d3d=false and problem dissapeared after that I assigned this bug to 2d team to check if there is any problem with d3d pipeline, in case everything is correct there, let me know and I will give additional info why the provided test case is not correct
07-11-2008