Index: /trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 16763)
+++ /trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 16764)
@@ -1330,4 +1330,11 @@
 
     /**
+     * The cursor hotspot constants {@link #DEFAULT_HOTSPOT} and {@link #CROSSHAIR_HOTSPOT} are relative to this cursor size
+     */
+    protected static final int CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO = 32;
+    private static final Point DEFAULT_HOTSPOT = new Point(3, 2);  // FIXME: define better hotspot for rotate.png
+    private static final Point CROSSHAIR_HOTSPOT = new Point(10, 10);
+
+    /**
      * Load a cursor image with a given file name, optionally decorated with an overlay image
      *
@@ -1345,5 +1352,4 @@
                                                 .setMaxSize(ImageSizes.CURSOROVERLAY)));
         }
-        hotSpot.setLocation("crosshair".equals(name) ? new Point(10, 10) : new Point(3, 2));
         ImageIcon imageIcon = imageProvider.get();
         Image image = imageIcon.getImage();
@@ -1361,8 +1367,9 @@
                 image = image.getScaledInstance(bestCursorSize.width, bestCursorSize.height, Image.SCALE_DEFAULT);
             }
-
-            hotSpot.x = hotSpot.x * bestCursorSize.width / width;
-            hotSpot.y = hotSpot.y * bestCursorSize.height / height;
-        }
+        }
+
+        hotSpot.setLocation("crosshair".equals(name) ? CROSSHAIR_HOTSPOT : DEFAULT_HOTSPOT);
+        hotSpot.x = hotSpot.x * image.getWidth(null) / CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
+        hotSpot.y = hotSpot.y * image.getHeight(null) / CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
 
         return image;
Index: /trunk/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java	(revision 16763)
+++ /trunk/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java	(revision 16764)
@@ -194,6 +194,4 @@
     }
 
-    public static final int ORIGINAL_CURSOR_SIZE = 32;
-
     /**
      * Test getting an image for a crosshair cursor.
@@ -215,8 +213,14 @@
     @Test
     public void testGetCursorImageWithOverlay() {
+        testCursorImageWithOverlay(1.0f);  // normal case
+        testCursorImageWithOverlay(1.5f);  // user has configured a GUI scale of 1.5 in the JOSM advanced preferences
+    }
+
+    private void testCursorImageWithOverlay(float guiScale) {
         if (GraphicsEnvironment.isHeadless()) {
             // TODO mock Toolkit.getDefaultToolkit().getBestCursorSize()
             return;
         }
+        GuiSizesHelper.setPixelDensity(guiScale);
         Point hotSpot = new Point();
         Image image = ImageProvider.getCursorImage("normal", "selection", hotSpot);
@@ -237,5 +241,6 @@
 
     private void assertCursorDimensionsCorrect(Point.Double originalHotspot, Image image, Point hotSpot) {
-        Dimension bestCursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(ORIGINAL_CURSOR_SIZE, ORIGINAL_CURSOR_SIZE);
+        int originalCursorSize = ImageProvider.CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
+        Dimension bestCursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(originalCursorSize, originalCursorSize);
         Image bestCursorImage = HiDPISupport.getResolutionVariant(image, bestCursorSize.width, bestCursorSize.height);
         int bestCursorImageWidth = bestCursorImage.getWidth(null);
@@ -243,6 +248,6 @@
         int bestCursorImageHeight = bestCursorImage.getHeight(null);
         assertEquals((int) Math.round(bestCursorSize.getHeight()), bestCursorImageHeight);
-        assertEquals(originalHotspot.x / ORIGINAL_CURSOR_SIZE * bestCursorImageWidth, hotSpot.x, 1 /* at worst one pixel off */);
-        assertEquals(originalHotspot.y / ORIGINAL_CURSOR_SIZE * bestCursorImageHeight, hotSpot.y, 1 /* at worst one pixel off */);
+        assertEquals(originalHotspot.x / originalCursorSize * bestCursorImageWidth, hotSpot.x, 1 /* at worst one pixel off */);
+        assertEquals(originalHotspot.y / originalCursorSize * bestCursorImageHeight, hotSpot.y, 1 /* at worst one pixel off */);
     }
 
