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: 4756347
Votes 0
Synopsis 1.4.1 Graphics.draw[Oval/Polygon] scatters boundary line
Category java:classes_2d
Reported Against 1.4.1
Release Fixed
State 11-Closed, Not Reproducible, bug
Priority: 4-Low
Related Bugs
Submit Date 01-OCT-2002
Description




FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

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

EXTRA RELEVANT SYSTEM CONFIGURATION :
 customer  PCG-883L Notebook with ATI Technologies Mobilt Radeon
display adaptor.

A DESCRIPTION OF THE PROBLEM :
Graphics.drawOval() or Graphics.drawPolygon() are generating
laterally scattered segments of the locus of the oval or
polygon.

REGRESSION.  Last worked in version 1.3.1

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.To see bug Compile BugPanel.java as-is
2.Run: java BugPanel
3.Click on panel(option - and drag it around)
4.Recompile after changing drawOval/fillOval to
drawRect/fillRect and rerun to see proper behaviour.
5.Same happens with drawPolygon/fillPolygon, but not
demonstated here.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expect a single normal (smooth) curve forming an oval.
Instead, one gets broken segments covering about  one third
of the curvve all around, and the remaining segments are drawn
at an x- customer  offset to + and - directions. Seems a period of
3 of the x-width. So we get three renderings of the oval all
with brolen curve segments

What should happen is a single smooth oval drawing

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.UIManager;

public class BugPanel extends JPanel implements MouseListener{

  private transient Dimension viewSize;
  private transient int viewHeight, viewWidth;
  private final static int VIEW_MARGIN = 10; // percentage of view dimensions
  private transient double x_origin, y_origin;
  private transient double x_width, y_height;
  private transient double x_delta, y_delta;
  private transient double min_xdel, min_ydel;
  private final static int XPAD = 5;
  private final static int YPAD = 5;
  protected transient Vector locations;
  Location grab;

    // HERE'S WHERE fillOval/drawOval are called.
    // Replace with fillRect/drawRect to see normal behaviour
  private void drawLocation(Graphics g, Location location) {
    Dimension d = getLocationSize(location);
    int w = d.width;
    int h = d.height;
    FontMetrics fm = g.getFontMetrics();
	if(location==grab) g.setColor(Color.lightGray);
	else g.setColor(Color.white);
//    g.fillRect(location.getX() - w/2, location.getY() - h/2, w, h);
    g.fillOval(location.getX() - w/2, location.getY() - h/2, w, h);
	g.setColor(Color.black);
	g.drawString(location.getName(), location.getX() - w/2 + XPAD, location.getY()
+ YPAD);
	g.setColor(Color.red);
//    g.drawRect(location.getX() - w/2, location.getY() - h/2, w, h);
    g.drawOval(location.getX() - w/2, location.getY() - h/2, w, h);
  }


  public BugPanel() {
    locations = new Vector();
	addMouseListener(this);
	MouseMotionAdapter mml = new MouseMotionAdapter(){
		//
//
//// Begin mouse motion listener
  public void mouseDragged(MouseEvent me) {
	// if grabbed set where
	if(grab!=null){
		grab.setX(me.getX()+(int)min_xdel);
		grab.setY(me.getY()+(int)min_ydel);
	}
	repaint();
  }

  public void mouseMoved(MouseEvent me) {
	  // No Mouse Button Down, so do nothing
  }
// End Mouse Motion Listener
//
//
  };
	addMouseMotionListener(mml);
	ComponentAdapter componentListener = new ComponentAdapter(){
		public void componentResized(ComponentEvent e) {
			viewHeight = (int)getHeight();
			viewWidth = (int)getWidth();
            }  };
	addComponentListener(componentListener);
  }

//
//
//// Begin mouse listener

		public void mouseClicked(MouseEvent me) {
                        Object src = me.getSource();
			if(locations.size() == 0){ // Create just one to demonstrate problem
                            System.out.println("Show scatter with Oval!");
				Location location = new Location("You may Drag this 'icon'
around",me.getX(),me.getY());
				locations.add(location);
			}
//			me.consume();
		}

		public void mousePressed(MouseEvent me) {
			// grab and drag nearest location
				double nearest = Double.MAX_VALUE;
				double proximity = Double.MAX_VALUE;
				min_xdel = min_ydel = 0.0;
				int x = me.getX();
				int y = me.getY();
				Enumeration e = locations.elements();
				e = locations.elements();
				while(e.hasMoreElements()) {
  					Location l = (Location)e.nextElement();
  					Dimension d = getLocationSize(l);
					x_delta = l.getX() - x;
					y_delta = l.getY() - y;
					proximity = (x_delta) * (x_delta) + (y_delta) * (y_delta);
					double  customer  = (d.width/2) * (d.width/2) + (d.height/2) * (d.height/2);
					// do not  customer  if you have not touched anything first
					// or if you have backed off from a previous  customer 
					// unless an alternative improves the last  customer 
					if ((nearest==Double.MAX_VALUE&&proximity<= customer )
						|| (nearest!=Double.MAX_VALUE&&proximity < nearest)) {
								grab = l;
					nearest = proximity;
					min_xdel = x_delta;
					min_ydel = y_delta;
  					}
				}
				if(grab!=null){
					grab.setX(x+(int)min_xdel);
					grab.setY(y+(int)min_ydel);
					}
		 repaint();
//			me.consume();
		}

		public void mouseReleased(MouseEvent me) {
        if(grab!=null){
			grab.setX(me.getX()+(int)min_xdel);
			grab.setY( me.getY()+(int)min_ydel);
            grab=null;
		 }
		 repaint();
//		 me.consume();
		}

    public void mouseEntered(MouseEvent me) {
    }

    public void mouseExited(MouseEvent me) {
    }

// End Mouse Listener
//
//


  public void initSize(Dimension size) {
	setPreferredSize(size);
	  viewSize = getPreferredSize();
	  viewHeight = (int)viewSize.getHeight();
	  viewWidth = (int)viewSize.getWidth();
	y_origin = viewHeight/VIEW_MARGIN;
	x_origin = viewWidth/VIEW_MARGIN;
	x_width = (double) viewWidth;
	y_height = (double) viewHeight;
  }

  public Dimension getLocationSize(Location location) {
    Graphics g = getGraphics();
    FontMetrics fm = g.getFontMetrics();
    int w = fm.stringWidth(location.getName()) + 2 * XPAD;
    int h = fm.getHeight() + 2 * YPAD;
	location.setW(w);
	location.setH(h);
    return new Dimension(w, h);
  }

    public void paint(Graphics g) {
/* Graphics.clearRect() was not needed pre JSDK1.3.x */
/* comment out for the effect that appeared in 1.3.x */
 g.clearRect(0,0,viewWidth,viewHeight);
    Enumeration l = locations.elements();
    while(l.hasMoreElements()){
      drawLocation(g, (Location)l.nextElement());
    }
	g.setColor(Color.black);
  }

//
//
//// Specify Location (made inner to fit into demo file)
public class Location {
  private String name;
  private int x, y, w, h;

  public Location(String name, int x, int y) {
    this.name = name;
    this.x = x;
    this.y = y;
  }
  public String getName() { return name;  }


  public int getX() { return x;  }

  public int getY() { return y;  }

  public int getW() { return w;  }

  public int getH() { return h;  }

  public void setX(int x) { this.x = x;  }

  public void setY(int y) { this.y = y;  }

  public void setW(int w) { this.w = w;  }

  public void setH(int h) { this.h = h;  }

  public void setName(String name) { this.name = name;  }

  }
// End Location
//
//
  public static void main(String[] args){
		try { // Toggle L&F between 'System' with 'CrossPlatform'
	    UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
	} catch (Exception exc) {
	    System.err.println("Error loading L&F: " + exc);
	}
		JFrame frame = new JFrame("DrawBugDemo: Click in pane for Demonstration");
                frame.addWindowListener(
                  new WindowAdapter() {
                    public void windowClosing(WindowEvent e) {
                        System.out.println("Also happens with drawPolygon!");
                        System.out.println("But not with with drawRect!");
                        System.out.println("Ciao!");
                        System.exit(0);}
                  }
                 );
		frame.setSize(new Dimension(420,300)); // Use Size of reference Frame
		frame.setLocation(20,30);
		BugPanel topPanel = new BugPanel();
		topPanel.setPreferredSize(new Dimension(420,140));
                frame.getContentPane().add(topPanel);
		frame.addMouseListener(topPanel); // This does not help symptom */
                frame.setVisible( true);
  }
}

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

CUSTOMER WORKAROUND :
None found
(Review ID: 165096) 
======================================================================
Work Around
Because this appears to be a bug in the graphics hw or driver for that particular video card, disabling ddraw (which punts to GDI for these cases) is a successful workaround for the problem:
	java -Dsun.java2d.ddoffscreen=false
(ddoffscreen disables our use of offscreen surfaces, so the back buffer is a BufferedImage instead)
	java -Dsun.java2d.noddraw=true
(noddraw disables ddraw completely, including copies to the screen).
Evaluation
Graphics.draw[Oval/Polygon] is owned by 2D.  
  xxxxx@xxxxx   2002-10-01

Not reproducible on my current desktop (Matrox g400); seems like a very
dcard/driver-version (and possibly resolution) dependent bug.  Drawing ovals
through Java2D simply ends up in GDI calls, so it seems like the GDI driver
for that graphics configuration is simply doing weird things with the 
oval rendering.  I've contacted the user to get specifics on their video
setup to see if I can get a similar testing configuration here to reproduce
the bug.

  xxxxx@xxxxx   2002-11-07

Verified with the user that the problem only occurs when we render using ddraw (actually our GDI punt) to the back buffer; our software rendering routines (to a BufferedImage back buffer) work fine.  Pretty clear that this is a driver or hardware bug since we simply call GDI and let it handle the primitive completely.  I'm leaving the bug open for now pending more information on driver versions (and hopefully the ability to reproduce the bug in-house), but I don't see what we can do here besides recommend a driver upgrade (which will hopefully fix the problem, assuming ATI has fixed whatever the bug was).

  xxxxx@xxxxx   2002-11-15

Just tested this with a later Radeon Mobility card (9700M) and cannot see the problem.  This has to be a card/driver-specific problem that we cannot affect; hopefully the bug is fixed in later drivers if it was a driver problem.  It certainly appears fixed in later hardware, such as the 9700M.  Closing the bug as Not Reproducible.

  xxxxx@xxxxx   2004-08-10
Comments
  
  Include a link with my name & email   

Submitted On 13-JAN-2003
actano
I have this problem on my machine too. 
Got a Matrox Millenium G200 AGP (8MB, SGRAM, RAMDAC 250 MHz,
Serial Number GAK 55921).
Software: Graphics BIOS 1.3-11, Disp.Driver: 5.00.2195.1010
(1.01.023) Matrox PowerDesk: 6.01.023 Microsoft DirectX: 7.0
Hope this helps you to reproduce the problem....


Submitted On 11-FEB-2003
aurchin
I have noticed a similar problem when drawing Line2D,
QuadCurve2D and CubicCurve2D using JDK 1.4.1 on an ATI
Radeon card.

I do not think that this is a driver or hardware bug as this
problem does not occur with JDK 1.3.1 - only 1.4.1!


Submitted On 11-FEB-2003
aurchin
Oops, I've had it pointed out that this could be a driver
problem as JDK 1.4 uses more DirectX acceleration than 1.3
(which ATI seem to have stuffed up :)



PLEASE NOTE: JDK6 is formerly known as Project Mustang