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: 4265778
Votes 198
Synopsis Java2D incorrectly renders objects with large coordinates
Category java:classes_2d
Reported Against 1.2.2 , 1.4.1 , tiger , mantis-rc
Release Fixed
State 6-Fix Understood, bug
Priority: 4-Low
Related Bugs 4376103 , 4858912
Submit Date 25-AUG-1999
Description


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) 
======================================================================
Posted Date : 2005-07-25 17:30:15.0
Work Around




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.
======================================================================
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.

  xxxxx@xxxxx   2001-03-23
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.
Posted Date : 2005-07-25 17:30:15.0
Comments
  
  Include a link with my name & email   

Submitted On 25-AUG-2000
epietrig
somehow related to bugs 4297004 and 4204453


Submitted On 09-NOV-2000
lerzeel
// Check out this crash application :
package com.eurotronics.test;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

/**
 * This program demonstrates (in three lines) that a 
Graphics (and Graphic2D)
 * object hangs when drawing a vector object that is larger 
than 32.000 pixels.
 *
 * Related bugs are 4265778, 4297004, 4204453,
 * 4376103, 4323072, 4250125, 4191132 (check out the 
evaluation)
 *
 * I submitted a bug report about the related bugs (at 2000-
11-08), and this is
 * what Sun told me :
 * &quot;All the mentioned bugs are open and under consideration&quot;
 *
 * Since 1998-11-18 ? They must be evaluating in in 
infinite loop I guess ;-)
 */
public class Crash
{
    static public void main(String[] args)
    {
        BufferedImage image = new BufferedImage
(100,100,BufferedImage.TYPE_INT_ARGB);
        Graphics graphics = image.createGraphics();
        for(int i=31900; i&lt;33000; i++) {System.out.println
(&quot;&quot;+i);graphics.drawLine(0,0,i,i);}
    }
}


Submitted On 17-NOV-2000
AaronAston
After much digging in the bug database, I have the 
following summary.  This bug seems to be related to bugs:
{4297004, 4204453, 4210466, 4114921}.  There is one more 
bug that is related that I can't find any longer.  A 
comment to that other bug suggested that the problem was 
actually related to stroking Java 2D shapes.  The commenter 
claimed that if g2d.setStroke(stroke) was not called before 
rendering large shapes that everything was fine.

I am reporting similar findings.  I am trying to render 
large lines with 1 pixel thickness.  The current way to do 
this with BasicStroke involves constructing a BasicStroke 
object with '0' specified as the line width.  Documentation 
on this site (one of the bug reports mentioned above?) 
specifies that 0 line thickness is actually converted to 
0.001 internally.  Then there is the ominous comment that 
this &quot;may cause underflows in some of the transformation 
matrices&quot; (or something very close to that).

In short, I have changed my rendering code to use 0.1 
thickness lines and all of my issues have disappeared.


Submitted On 28-NOV-2000
epietrig
Everything is NOT fine even if you don't call the  setStroke
method (I still get the JVM to crash when I try to draw very
large shapes), but it is true that things get even worse
when you use a special stroke. For instance, I draw some
objects with a dashed contour, and when they become very
large (zooming in), it takes a very long time to draw the image.


Submitted On 26-FEB-2001
xorxor
There are many other bugs that appear to be duplicates of 
this bug: 4191132, 4204453, 4249708, 4250125, 4252578, 
4297004, 4323072, 4335162, and 4376103.

A similar problem exists when drawing large antialiased 
shapes -- see bugs 4190780 and 4311665.


Submitted On 14-MAY-2001
lerzeel
We have implemented the software clipping ourselves. Not an 
easy solution (needed three classes to do it), but it 
works. The emphasis is on easy integration into existing 
code. People that are interested can contact me.


Submitted On 02-AUG-2001
macpeep
Clipping is really something that app developers themselves 
should handle. Sure, the 2D API should also provide it for 
you but if you want any kind of performance from your app, 
you're insane to draw things that are outside the viewport. 
If you're leaving clipping to the 2D API, you're doing a 
lot of work for no good since a large portion of your 
processing is for things that will not even be drawn. 
Saying that "this task belongs in the implementation of 
Graphics2D" is just plain wrong.


Submitted On 27-AUG-2001
xorxor
In response to "macpeep" above:

I agree that trivial object culling should be performed by 
the application -- objects that lie completely outside the 
viewport should not be drawn at all.  However, the more 
difficult case is an object that lies partially within the 
viewport.  This type of clipping is not trivial to 
implement, and it's this task that belongs in the 
implementation Graphics2D.


Submitted On 05-SEP-2001
macpeep
xorxor: Well.. GDI under Windows 9x only supports 16 bit 
coordinates, which are large enough anyway. Under NT / 
W2K / XP, you get a full 32 bit. Even so, it's insanity to 
leave it to GDI / Java2D to do clipping. It's just asking 
for trouble. Any decent app that cares about performance 
should perform clipping themselves. Like the map example 
someone mentioned.. If you have a 1000km long border and 
zoom in on 1m of it, the end point coordinates will be 
absolutely astronomical. Feeding that stuff to rendering is 
just plain and simply wrong. It will fail at some point - 
it's just a matter of if it runs out at 16 bits or 32 bits.


Submitted On 12-SEP-2001
xorxor
macpeep: I am well aware of the 16-bit and 32-bit 
limitations of GDI, and I have much experience implementing 
this sort of clipping in a mapping application.  Clipping 
is a pain, especially clipping complex polygons, and it's 
something that application developers shouldn't have to 
implement themselves.

Since Java2D specifies coordinates in floating-point, there 
is no problem dealing with coordinates of huge magnitude.  
Java2D already has to process these floating-point 
coordinates to convert them into integers for GDI.  I claim 
that Java2D should perform its own clipping in the floating-
point domain, *if* the conversion from floating-point to 
integers would result in coordinates that are greater than 
16 bits.  Why is this an unreasonable request?


Submitted On 24-SEP-2001
mthornton
The insanity would be doing your own full clipping. To 
avoid visual artefacts when scrolling you have to exactly 
match the line drawing algorithm used by the underlying 
graphics implementation. This is rather difficult, 
especially given that the Windows NT/2000 use a different 
algorithm to Windows 9x (yes different pixels are set in 
some cases). Even more fun with filled shapes bounded by 
bezier curves.
The application should clip out objects (and drawing 
primitives) which are completely invisible, but should not 
attempt to clip partially visible primitives.
As for 16 bits being adequate, I've worked with devices 
which had native coordinates which exceeded 16 bits (any 
large plotter or digitiser will exceed 16 bits).


Submitted On 28-JAN-2002
NormanCookX
This bug is still alive in:

java version "1.4.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 
1.4.0-rc-b91)
Java HotSpot(TM) Client VM (build 1.4.0-rc-b91, mixed mode)

Try the code in bug id 4323072.
If the zoom-scale is greater then 1000000 drawing will fail.
It seems to be a clipping-problem when using great double 
values.


Submitted On 03-FEB-2002
FEBERT
This problem was not too serious in JDK1.3.x versions but totally useless in 1.4.x versions. The 1.3 versions I could zoom my pictures to 60,000 times bigger without problem, but in 1.4.0-rc I can not zoom bigger than 140 times...


Submitted On 12-DEC-2002
drwil
My email address if wil@amristar.com.au (I clicked the tick
box?).

Any information regarding the current state of this bug in
1.4 plugins is much appreciated. I use Linux/X with a 1.3
plugin and also test (mostly) on Windows platforms.

Oh, if the native calls choose not to draw the line that
would be better than going into hyperspace!


Submitted On 12-DEC-2002
drwil
We have been developing a client/server mapping application
(www.idelve.net) over the last few years. It allows
interactive panning and zooming and included client-side
rendering. This bug is all that stands in the way of an
updated and more complete demo (current ones over a year old).

The problem is that the application cannot easily deal with
work arounds. If you know what the data is (e.g. rendering
predefined vectors) you can keep tabs on the largest line
segment (so to avoid recaculating it on the fly, similar to
maintaining the objects bounds (as seen on other related
bugs)). With the largest line segment you can screen
polylines so that these are drawn in a special (inefficient)
way to manually handle line segments >32K (or some defined
value). However this sucks for lines drawn, edited and
otherwise manipulated by users.

In out application the user can draw a polyline while
zooming /panning. Hence the underlying drawing routines
(well, our graphics adpapter which backs onto
java.awt.Graphics or java.awt.Graphics2) needs to know the
length in pixels of the line segments of each drawable
object at the current drawing resolution (which is changing
all the time). The overheads in making such calculations a
quite heavy.

It would seem to me that the native drawing routines should
cater for this. From all observed behaviours the actual
"drawLine" (or drawPolyline, etc) is done natively. I can
handle (well, it's acceptable) a virtual canvas size of
2**32 squared... so the native calls should handle values
which cause the underlying GUI to overflow and screen these
as efficiently as possible at the lowest level.

i.e. "This line breaks out GUIs internal constraints, clip
it here".

This is the best way to deal with the problem IMHO.

I am curious to see Ierzeel's work arounds but based on the
graphics adapters and different coordinate systems we're
using it may not suit.

Wil


Submitted On 09-FEB-2003
dnoyeB
is this related to WindowsLookAndFeel failing with
largeTreeModel???


Submitted On 09-AUG-2004
john_777
testing


Submitted On 26-DEC-2004
Mahe
This bug has been rectified in jdk 1.5 without turning off the Antialiasing


Submitted On 24-JUN-2006
mhoesch
Had the same problems, when a JTable in a JScrollPane gets to much entries (>100000 rows), and the user scrolls to that area, the drawn UI is simply not displayed correctly anymore.

Marc Höschele



PLEASE NOTE: JDK6 is formerly known as Project Mustang