JDK-6921602 : Paint.createContext receives incorrect userBounds when antialiasing is on
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6u10,7
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic,linux
  • CPU: generic,x86
  • Submitted: 2010-02-01
  • Updated: 2011-05-11
  • Resolved: 2011-05-11
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Client VM (build 14.2-b01, mixed mode, sharing)

java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
Java HotSpot(TM) Client VM (build 14.3-b01, mixed mode, sharing)

I have tried 1.6.0_12 and 1.6.0_16 on Linux and 1.6.0_17 on Windows XP and they all fail. 1.6.0_10 and earlier releases work OK.

ADDITIONAL OS VERSION INFORMATION :
Linux lilac 2.6.17-5mdv #1 SMP Wed Sep 13 14:32:31 EDT 2006 i686 AMD Athlon(tm) XP 2000+ GNU/Linux

(have seen on other linux systems as well)

Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
java.awt.Paint.createContext receives incorrect userBounds when antialiasing is turned on. The userBounds is the same as the deviceBounds even though there is a transform.

If you turn off antialiasing, the userBounds are correctly set to the bounds of the shape before the transform has been applied.

I submitted this bug in March of this year, for 1.6.0_12. It may not be catastrophic, but I'd at least like to see it acknowledged!

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the program below. See the blue rectangle with no gradient. Check the output, and the userBounds are the same as the deviceBounds.

2.  Uncomment the setRenderingHints call in the paintComponent method and run again. See a blue gradient in the rectangle, and in the output the userBounds should be [x=0.0,y=0.0,w=200.0,h=10.0]


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
see step 2 above
ACTUAL -
see step 1 above

REPRODUCIBILITY :
This bug can be reproduced always.

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

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.ColorModel;
import javax.swing.*;



public class Gradx extends JComponent {

    Color blue1 = new Color(200,210,230);
    Color blue2 = new Color(100,120,150);
    Paint grad = new GradientPaint2(blue1, blue2);
    Rectangle2D rect = new Rectangle2D.Double(0, 0, 200, 10);
    AffineTransform xform = AffineTransform.getTranslateInstance(300, 20);


    public Gradx() {
	super();
	super.setPreferredSize(new Dimension(600, 100));
    }


    public void paintComponent (Graphics g) {

	Graphics2D g2 = (Graphics2D) g.create();
	g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
	  RenderingHints.VALUE_ANTIALIAS_ON);

	g2.transform(xform);
	g2.setPaint(grad);

	System.out.println("g2.transform=" + g2.getTransform());
	System.out.println("shape=" + rect);
	System.out.println("antialiasing="
		   + g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING));
	
	g2.fill(rect);
	g2.dispose();
    }


    static class GradientPaint2 implements Paint {

	private Color c1, c2;

	public GradientPaint2 (Color c1, Color c2) {
	    this.c1 = c1;
	    this.c2 = c2;
	}

	public int getTransparency() { return Paint.TRANSLUCENT; }

	public PaintContext createContext
	    (ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds,
	     AffineTransform xform, RenderingHints hints) {

	    System.out.println("deviceBounds=" + deviceBounds);
	    System.out.println("userBounds=" + userBounds);
	    System.out.println("xform=" + xform);
	    
	    GradientPaint g = new GradientPaint
		((float)userBounds.getX(), (float)userBounds.getY(), c1,
		 (float)(userBounds.getX() + userBounds.getWidth()),
		 (float)(userBounds.getY() + userBounds.getHeight()), c2,
		 false);

	    return g.createContext(cm, deviceBounds, userBounds,
				   xform, hints);
	}
    }


    public static void main (String[] args) {

	SwingUtilities.invokeLater(new Runnable() {
	    public void run() {
	
		Gradx gradx = new Gradx();

		JFrame frame = new JFrame("Gradient Example");
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(gradx, BorderLayout.CENTER);
		frame.pack();
		frame.setVisible (true);
	    }
	});
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
You can apply the inverse of the transform to the deviceBounds to get the correct userBounds, but you won't get exactly the same rectangle if there is a rotation, and the transform may not be invertible.

Comments
EVALUATION Apparently introduced by the fix for 6766342: Improve performance of Ductus rasterizer
09-05-2011