Skip to content

Fix cursor loading incorrect image size when ImageData is unavailable at requested zoom #2317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

arunjose696
Copy link
Contributor

@arunjose696 arunjose696 commented Jul 15, 2025

Description

Before this change, the cursor used DPIUtil.validateAndGetImageDataAtZoom() to get image data. However, this method could return image data at a different zoom level if the exact match wasn't available from the ImageDataProvider. As a result, the cursor could be scaled incorrectly, since the returned image data was assumed to match the requested zoom.

With this change, a temporary Image is created, and Image.getImageData(zoom) is called to get properly scaled image data for the requested zoom level.

Steps to reproduce:

Run the below snippet at 150% monitor zoom. The ImageDataProvider in the snippet returns image data only for zoom levels 100 and 200.

Without this change
When run without any swt.autoScale VM argument, the cursor size was incorrectly scaled to 60×60.
When run with -Dswt.autoScale=quarter, the cursor is 30x30.

With this current fix applied
The cursor is now correctly sized (e.g., 45×45 at 150% zoom).

package org.eclipse.swt.snippets;

import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.widgets.*;

public class Snippet118 {

   public static void main(String[] args) {

      final Display display = new Display();
      final Shell shell = new Shell(display);
      Rectangle bounds = shell.getBounds();

      shell.setLocation((int) (bounds.width * 0.9f), 100);
      shell.setText("Snippet 118");
      shell.setSize(1000, 1000);

      final Cursor[] cursor = new Cursor[1];
      final ImageData[] imageData = new ImageData[1];



      shell.addPaintListener(event -> {

         GC gc = event.gc;

         ImageData oneImageData = imageData[0];
         if (oneImageData != null) {

            gc.drawText("Cursor width %d  - height %d".formatted(
                  oneImageData.width,
                  oneImageData.height), 10, 50, true);
         }

         int i = 1;


         int monitorZoom = DPIUtil.getNativeDeviceZoom();
         int deviceZoom = DPIUtil.getDeviceZoom();
         float devScale = deviceZoom / 100f;

         gc.drawText("Monitor zoom = %d".formatted(monitorZoom), 10, 140);

         int yPos = 400;
         int tickHeight = 10;

         for (int tickIndex = 0; tickIndex < 11; tickIndex++) {

            int xPos = 100 + tickIndex * 10;
            int yOffset = 0;

            if (tickIndex % 3 == 1) {
               yOffset = 20;
            } else if (tickIndex % 3 == 2) {
               yOffset = 40;
            }

            int xPosUnscaled = (int) (xPos / devScale);
            int YPosUnscaled = (int) (yPos / devScale);

            gc.drawLine(xPosUnscaled, YPosUnscaled, xPosUnscaled, YPosUnscaled + tickHeight);
            gc.drawText(Integer.toString(tickIndex * 10), xPosUnscaled - 5, YPosUnscaled + 12 + yOffset);
         }
      });


      ImageDataProvider imageDataProvider = zoom -> {
  		if(zoom==100)
  			return new ImageData(30, 30, 1, new PaletteData(new RGB(255, 0, 0)));
  		else if(zoom==200)
  			return new ImageData(60, 60, 1, new PaletteData(new RGB(255, 0, 0)));
  		else
  			return null;
  	};


      cursor[0] = new Cursor(display, imageDataProvider, 0, 0);
      shell.setCursor(cursor[0]);


      shell.redraw();

      shell.open();
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch())
            display.sleep();
      }

      if (cursor[0] != null)
         cursor[0].dispose();
      display.dispose();
   }
}

Note : This snippet is adapted from [issue #2057](#2057 (comment) to get the scales

Previously, the cursor used DPIUtil.validateAndGetImageDataAtZoom() to
retrieve image data, which may return Imagedata at a different zoom
level than requested if ImageData for the exact zoom is unavailable.
This led to incorrect scaling when the returned image data was treated
as if it matched the requested zoom.

This commit replaces that logic with a temporary Image and calling
Image.getImageData(zoom) to  retrieve  image data for the requested zoom
level.
Copy link
Contributor

Test Results

   546 files  ±0     546 suites  ±0   31m 0s ⏱️ -1s
 4 407 tests ±0   4 390 ✅ ±0   17 💤 ±0  0 ❌ ±0 
16 713 runs  ±0  16 586 ✅ ±0  127 💤 ±0  0 ❌ ±0 

Results for commit 5a39650. ± Comparison against base commit 95b46b6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cursor does not load image data in proper size
1 participant