JDK-4212593 : The Toolkit.createCustomCursor does not check absence of the image of cursor
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.2.2
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_2.5.1
  • CPU: sparc
  • Submitted: 1999-02-18
  • Updated: 1999-05-24
  • Resolved: 1999-05-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.3.0 kestrelFixed
Related Reports
Relates :  
Relates :  
Description

Name: akC57697			Date: 02/18/99



 The Toolkit.createCustomCursor does not check absence of the image of cursor.

 The javadoc says:
" 
public Cursor createCustomCursor(Image cursor,
                                 Point hotSpot,
                                 String name)
                          throws IndexOutOfBoundsException

      Creates a new custom cursor object.
      Parameters:
            image - the image to display when the cursor is active.
            hotSpot - the X and Y of the large cursor's hot spot. The hotSpot values
            must be less than the Dimension returned by getBestCursorSize().
            name - a localized description of the cursor, for Java Accessibility use.
      Throws:
            IndexOutOfBoundsException - if the hotSpot values are outside the bounds
            of the cursor.
"

---------------------------------------8-<-----------------------------------
import java.awt.Toolkit;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.Canvas;


public class Test {

    public static void main(String argv[]) {
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension dk = tk.getBestCursorSize(16, 16);
        Image image = tk.getImage("NON_EXISTING_FILE.gif");
        if (image == null) {
            System.out.println("No image has loaded");
            System.exit(0);
        }
        Cursor c = null;
        Canvas cp = new Canvas();
        Point p = new Point(0, 0);
        try {
            c = tk.createCustomCursor(image, p, "Test");
        } catch (Exception e) {
            System.out.println("image:" + image + " with the size: "
                    + image.getWidth(cp) + " x " + image.getHeight(cp));
            System.out.println("1 getBestCursorSize:" + dk);
            System.out.println("Values are:" + p);
            System.out.println("The cursor size is " + dk);
            System.out.println("Unexpected " + e);
            e.printStackTrace();
            System.exit(0);
        }
        System.out.println("OKAY");
        System.exit(0);
    }
}
---------------------------------------8-<-----------------------------------
(No JIT to see the trace)
image:sun.awt.motif.X11Image@7f3eb146 with the size: -1 x -1             
1 getBestCursorSize:java.awt.Dimension[width=16,height=16]
Values are:java.awt.Point[x=0,y=0]
The cursor size is java.awt.Dimension[width=16,height=16]
Unexpected java.lang.NegativeArraySizeException
java.lang.NegativeArraySizeException
	at sun.awt.CustomCursor.<init>(CustomCursor.java:69)
	at sun.awt.motif.X11CustomCursor.<init>(X11CustomCursor.java:45)
	at sun.awt.motif.MToolkit.createCustomCursor(MToolkit.java:377)
	at Test.main(Test.java:23)

java full version "JDK-1.2.2-E"

-----------------------------------------------------------------
 * @(#)CustomCursor.java	1.7 99/01/11
...
line 38 MediaTracker tracker = new MediaTracker(c);
        tracker.addImage(cursor, 0);
        try {
            tracker.waitForAll();
        } catch (InterruptedException e) {
        }                                      <--tracker.isErrorAny()? would catch this
        int width = cursor.getWidth(c);
        int height = cursor.getHeight(c);
...


======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: kestrel FIXED IN: kestrel INTEGRATED IN: kestrel
14-06-2004

EVALUATION If we fix the bug in the 1.2.1 time frame, we could throw an exception if the width or height of the image is negative. If we fix this in the kestrel time frame, we may have to take a different approach. By this time, developers may be exploiting the bug as an easy way to hide the cursor. david.mendenhall@eng 1999-03-02 The JCK team will exclude this test for 1.2.1, as they did for 1.2. We will fix the bug in kestrel. david.mendenhall@eng 1999-03-02 ###@###.### 1999-05-17 ----- ###@###.###: On Tue, May 04, 1999 at 03:41:0p -0700, David Mendenhall wrote: > Yes, at this point, I would just default an invalid image (one with width > or height of -1) to an empty cursor. This will give developers an easy way to > hide the cursor. You will need to update the javadoc to reflect this as well. > tdv: take a look at this variant. The problem is that under Win32 invalid image size -1x-1 is corrected by getBestCursorSize call (to 32x32), but under Solaris it's not which causes the exception during image array creation (actually, not only there). So I come up with the following: in case of invalid image changing size to 1x1 and hotSpot to 0x0 (to prevent possible IndexOutOfBoundsException when checking the hotSpot to be inside the cursor). So under Win32 the cursor will be 32x32 and under Solaris 8x8, both use image arrays with zeros which makes whem hidden. On Mon, May 10, 1999 at 05:08:0p -0700, David Mendenhall wrote: > Why can't we change the Solaris code so that it corrects the size just like > Windows does? Solaris code calls XQueryBestCursor to obtain the largest cursor size that could be dislpayed on the screen. This function takes uint's for width and height, but we're passing -1's (65535), so the function returns not very useful 65535s. Under Solaris it's OK to have a cursor of such size, the only restriction is that under Solaris 2.6 it should be 8 divisable (which is already being handled by X11CustomCursor.createNativeCursor). So in some sence what I suggest is to correct wrong negative dimensions. Probably, we should do it in X11CustomCursor.getBestCursorSize instead of CustomCursor.createCustomCursor since under Win32 we obtain best cursor size w/o taking passed width and height into account - that's why it works OK w/o changing a line under Win32. > Why is an array of all zeroes assumed to be transparent? It could > just as easily imply all black, right? No, it can't because 0 means (in particular) the transparent color (it has transparent bit set to 0). Here is a quote from X11CustomCursor.createNativeCursor code: // do not include transparent color if ((pixels[ip] & 0xff000000) == 0) continue; where pixels[] is an array of pixels (zeros in our case). So the black in this case would be, say, 0xff000000 and white is 0xffffffff. -- Some notes: even when we adjusted cursor size in X11CustomCursor.getBestCursorSize, we still should change hotspot to 0x0 in the constructor of CustomCursor.otherwise one could get IndexOutOfBoundsException instead of cursor hiding. ------------------------------------- tdv --------------
11-06-2004

WORK AROUND Name: akC57697 Date: 02/18/99 ======================================================================
11-06-2004

SUGGESTED FIX ###@###.### 1999-05-17 ------- CustomCursor.java ------- *** /tmp/d5Z4wo_ Mon May 17 15:47:25 1999 --- CustomCursor.java Mon May 17 15:20:35 1999 *************** *** 44,49 **** --- 44,58 ---- int width = cursor.getWidth(c); int height = cursor.getHeight(c); + // Fix for bug 4212593 The Toolkit.createCustomCursor does not + // check absence of the image of cursor + // If the image is invalid, the cursor will be hidden (made completely + // transparent). In this case, getBestCursorSize() will adjust negative w and h, + // but we need to set the hotspot inside the image here. + if (tracker.isErrorAny() || width < 0 || height < 0) { + hotSpot.x = hotSpot.y = 0; + } + // Scale image to nearest supported size. Dimension nativeSize = toolkit.getBestCursorSize(width, height); if (nativeSize.width != width || nativeSize.height != height) { ------- X11CustomCursor.java ------- *** /tmp/d0RyE3W Mon May 17 15:48:53 1999 --- X11CustomCursor.java Fri May 14 10:29:48 1999 *************** *** 50,56 **** */ public static Dimension getBestCursorSize( int preferredWidth, int preferredHeight) { ! Dimension d = new Dimension(preferredWidth, preferredHeight); queryBestCursor(d); return d; } --- 50,62 ---- */ public static Dimension getBestCursorSize( int preferredWidth, int preferredHeight) { ! ! // Fix for bug 4212593 The Toolkit.createCustomCursor does not ! // check absence of the image of cursor ! // We use XQueryBestCursor which accepts unsigned ints to obtain ! // the largest cursor size that could be dislpayed ! Dimension d = new Dimension(Math.abs(preferredWidth), Math.abs(preferredHeight)); ! queryBestCursor(d); return d; } ------- Toolkit.java ------- *** /tmp/d0Y9wqy Mon May 17 15:49:40 1999 --- Toolkit.java Mon May 17 15:19:54 1999 *************** *** 781,786 **** --- 781,788 ---- /** * Creates a new custom cursor object. + * If the image to display is invalid, the cursor will be hidden (made + * completely transparent), and the hotspot will be set to (0, 0). * @param image the image to display when the cursor is active. * @param hotSpot the X and Y of the large cursor's hot spot. The * hotSpot values must be less than the Dimension returned by
11-06-2004