JDK-4265778 : Java2D incorrectly renders objects with large coordinates
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.2.2,1.4.1,1.4.2,5.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic,linux,windows_xp
  • CPU: generic,x86
  • Submitted: 1999-08-25
  • Updated: 2009-06-25
Related Reports
Duplicate :  
Relates :  
Description
Name: wl91122			Date: 08/25/99


Java2D behaves incorrectly (and very unpredictably) when rendering objects with large coordinates.

Our mapping application typically has to render lines and polygons with very large coordinates.  For 
example, your window may be displaying a very small portion of California, but the application may 
have to fill California's entire border.  We need the rendering behavior to be very well-defined (with 
efficient clipping) under JDK 1.2.

In JDK 1.1, the Graphics interface used ints to specify the coordinates to be rendered.  However, the 
actual rendering was performed by the underlying OS graphics system and was therefore constrained 
by that system's coordinate limits.  For instance, Windows GDI uses shorts for coordinates, so JDK 1.1 
didn't have well-defined behavior for coordinates larger than shorts.

In JDK 1.2, the Graphics2D interface allows rendering of Shape objects, which can be specified with 
float or double coordinates.  Since the Graphics2D implementation provides some features that are
not available in Windows GDI (such as anti-aliasing), I assumed that this implementation performed 
all of its own rendering without using GDI.  If this is indeed the case, then the implementation should 
have well-defined behavior when rendering all objects, with coordinates spanning the full range of 
float and double values.

The following program illustrates how poorly defined the current rendering behavior is in JDK 1.2.2, 
running under Windows NT 4.0 and Windows 98.  You can choose one of four rendering cases by 
specifying 1, 2, 3, or 4 as a parameter on the command line.  Case 1 correctly draws a line with large 
coordinates.  Case 2 tries to draw the same line into an offscreen Image, but it appears to hang the 
Java VM.  Case 3 tries to fill a polygon with large coordinates, but it quickly draws nothing.  Case 4 
correctly fills the same polygon in an offscreen Image, but it takes several minutes to do so -- as if 
the clipping is being performed on each scan line.

In this sample code, I've used Graphics.drawLine and Graphics.fillPolygon to illustrate the 
behavior.  I've gotten the same results using a GeneralPath with Graphics2D.draw and 
Graphics2D.fill.

import java.awt.*;
import java.awt.event.*;

public class RenderBug extends Canvas {
  
  int m_paintCase;
  
  RenderBug(int num) {
    m_paintCase = num;
  }
  
  public void paint(Graphics g) {
    Image image;
    
    switch (m_paintCase) {
      case 1:
        // This correctly and quickly draws the line.
        drawBadLine(g);
        break;
        
      case 2:
        // This hangs the VM.
        image = createImage(640, 480);
        drawBadLine(image.getGraphics());
        g.drawImage(image, 0, 0, this);
        break;
        
      case 3:
        // This incorrectly (but quickly) draws nothing.
        fillBadPolygon(g);
        break;
        
      case 4:
        // This correctly (but very slowly) fills the polygon.
        image = createImage(640, 480);
        fillBadPolygon(image.getGraphics());
        g.drawImage(image, 0, 0, this);
        break;
    }
  }


  void drawBadLine(Graphics g) {
    System.out.println("Drawing line...");
    g.drawLine(0, 0, 55000, 20000);
    System.out.println("Line is drawn.\n");
  }

  
  void fillBadPolygon(Graphics g) {
    int[] x = { -90000000, 300, -40000000 };
    int[] y = { -30000000, 300, -70000000 };
    System.out.println("Filling polygon...");
    g.setColor(Color.green);
    g.fillPolygon(x, y, 3);
    System.out.println("Polygon is filled.\n");
  }

  
  public static void main(String[] args) {
    int num = 0;
    if (args.length == 1) {
      try {
        num = Integer.parseInt(args[0]);
      } catch (NumberFormatException ignore) {}
    }
    if (num < 1 || num > 4) {
      System.out.println("Usage: java RenderBug { 1 | 2 | 3 | 4 }");
    } else {
      Frame frame = new Frame("DrawImage");
      Canvas canvas = new RenderBug(num);
      frame.setSize(640, 480);
      frame.add("Center", canvas);
      frame.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
      frame.show();
    }
  }
}
(Review ID: 94393) 
======================================================================

Comments
EVALUATION This bug was fixed for X11 renderer (fix of the 4943522) and for all ones in anti-aliasing mode (as fix of the 4896773). But it is still not fixed for windows GDI Renderer which has pretty narrow boundaries in case of windows 98/ME (which is still not eolned) with 16-bit gdi. I'm not sure about accelerated pipelines. I guess the result for them will depend on particular driver/hardware configuration. We are not completely satisfied with the solution in the X11 and AA pipelines because we just clamp large coordinates to the appropriate boundaries. We plan (as permanent solution) to perform precise clipping of the primitives. It's pretty complex task especially in case of such primitives as bezier curves.
25-07-2005

WORK AROUND Name: wl91122 Date: 08/25/99 The only workaround is to clip the coordinates ourselves. We can crudely truncate the coordinates to shorts, or we can use a more sophisticated clipping algorithm. However, this task belongs in the implementation of Graphics2D -- preferably in native code. We'd like to avoid the performance overhead of doing our own clipping, and I don't think it's unreasonable to expect well-defined rendering behavior from Graphics2D. ======================================================================
26-09-2004

EVALUATION Test cases 2 and 4 are being addressed with the fix of bug 4376103. The deficiencies of the platform renderers and our reliance on them without a workaround will still be a problem even after 4376103 is fixed. This bug provides a good test case for those additional problems. It is also interesting to note that whereas we know that X11 is incapable of dealing with coordinates beyond 16 bits because of its interfaces and protocols, the GDI interface that we use for filling rectangles uses an array of POINT structures which use 32-bit fields to store the coordinates. Unfortunately, it looks like they don't support the full 32-bit coordinate space even if their interface would imply that they do. Also, this appears to be OS and maybe even display card dependent. On my NT box with an ATI card, cases 1 and 3 both work just fine, for instance. jim.graham@Eng 2001-03-23
23-03-2001