Skip to content

Conversation

@arunjose696
Copy link
Contributor

@arunjose696 arunjose696 commented Sep 26, 2025

The drawable on a GC can be null this would result in a null pointer error in GC#calculateZoomForImage as we check if the drawable is not autoScalable.

Expand for Code to trigger nullpointer
package org.eclipse.swt.snippets;

import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class Snippet386 {

    public static void main(String[] args) {
        Display display = new Display();

        Image[] images = new Image[] {
            new Image(display, createImageDataProvider())
        };

        String[] descriptions = new String[] {

            "ImageDataProvider with fixed font size for a given zoom",

        };

        Slice[] slices = {
            new Slice("Full", 0.0, 0.0, 1.0, 1.0)
        };

        createShellWithImages(display, images, descriptions, slices, "Snippet 386 - Flipped Layout");
    }



    private static ImageDataProvider createImageDataProvider() {
        return new ImageDataProvider() {
            @Override
            public ImageData getImageData(int zoomLevel) {
                int scaleFactor = zoomLevel / 100;
                return createScaledTextImageData(100 * scaleFactor, 100 * scaleFactor);
            }
        };
    }



    private static ImageData createScaledTextImageData(int width, int height) {
        Display display = Display.getDefault();
        String text = "abcd";

        int fontSize = Math.max(1, height / 100);
        Font font = new Font(display, "Arial", fontSize, SWT.NORMAL);

        Image tmp = new Image(display, 1, 1);
        GC measureGC = new GC(tmp);
        measureGC.setFont(font);
        Point textExtent = measureGC.textExtent(text);
        measureGC.dispose();
        tmp.dispose();

        double scale = Math.min((double) width / textExtent.x, (double) height / textExtent.y);
        font.dispose();
        font = new Font(display, "Arial", Math.max(1, (int) (fontSize * scale)), SWT.NORMAL);

        Image image = new Image(display, width, height);
        GC gc = new GC(image);
        gc.setFont(font);
        gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
        gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
        gc.fillRectangle(image.getBounds());

        gc.setLineWidth(Math.max(1, width / 20));
        gc.drawLine(0, 0, width / 2, height);

        Point newTextExtent = gc.textExtent(text);
        gc.drawText(text, (width - newTextExtent.x) / 2, (height - newTextExtent.y) / 2, true);

        gc.dispose();
        ImageData data = image.getImageData();

        image.dispose();
        font.dispose();

        return data;
    }

    static class Slice {
        String name;
        double xFrac, yFrac, wFrac, hFrac;
        Slice(String name, double x, double y, double w, double h) {
            this.name = name;
            this.xFrac = x;
            this.yFrac = y;
            this.wFrac = w;
            this.hFrac = h;
        }
    }

    private static void createShellWithImages(Display display, Image[] images, String[] descriptions, Slice[] slices, String title) {
        Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.MAX | SWT.RESIZE);
        shell.setText(title);
        shell.setLayout(new FillLayout());

        ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
        Canvas canvas = new Canvas(scrolledComposite, SWT.DOUBLE_BUFFERED);
        scrolledComposite.setContent(canvas);
        scrolledComposite.setExpandHorizontal(true);
        scrolledComposite.setExpandVertical(true);

        int boxW = 500, boxH = 500, gap = 20;
        int titleHeight = 20, descHeight = 40, sliceHeaderHeight = 30;

        int rows = images.length;
        int cols = slices.length;

        int canvasWidth = (boxW + gap) * cols + gap;
        int canvasHeight = (boxH + titleHeight + gap) * rows + descHeight + sliceHeaderHeight;
        canvas.setSize(canvasWidth, canvasHeight);
        scrolledComposite.setMinSize(canvasWidth, canvasHeight);

        canvas.addListener(SWT.Paint, e -> {
            // Column headers
            for (int col = 0; col < cols; col++) {
                int x = col * (boxW + gap) + gap;
                Font font = new Font(display, "Arial", 18, SWT.NORMAL);
                e.gc.setFont(font);
                e.gc.drawText(slices[col].name, x, 0, true);
                font.dispose();

            }

            // Rows
            for (int row = 0; row < rows; row++) {
                Image image = images[row];
                Rectangle rect = image.getBounds();
                int y = row * (boxH + titleHeight + gap) + descHeight + sliceHeaderHeight;

                Font font = new Font(display, "Arial", 18, SWT.NORMAL);
                e.gc.setFont(font);
                e.gc.drawText(descriptions[row], 0, y - 10, true);
                font.dispose();

                for (int col = 0; col < cols; col++) {
                    Slice s = slices[col];
                    int x = col * (boxW + gap) + gap;

                    int srcX = (int) (rect.width * s.xFrac);
                    int srcY = (int) (rect.height * s.yFrac);
                    int srcW = (int) (rect.width * s.wFrac);
                    int srcH = (int) (rect.height * s.hFrac);

                    int boxTop = y + titleHeight;
                    e.gc.drawRectangle(x, boxTop, boxW, boxH);


                    e.gc.drawImage(image, srcX, srcY, srcW, srcH, x, boxTop, boxW, boxH);

                }
            }
        });

        shell.setMaximized(true);
        shell.open();

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

        for (Image img : images) img.dispose();
        display.dispose();
    }
}

Issue was caused by #2507

The drawable on a GC can be null this would result in a null pointer
error in GC#calculateZoomForImage as we check if the drawable is not
autoScalable.
@github-actions
Copy link
Contributor

Test Results

  118 files  + 7    118 suites  +7   11m 32s ⏱️ -21s
4 577 tests +55  4 554 ✅ +48  17 💤 +3  6 ❌ +5 
  298 runs  +56    288 ✅ +47   4 💤 +3  6 ❌ +6 

For more details on these failures, see this check.

Results for commit c5bfc29. ± Comparison against base commit 00106b4.

This pull request removes 1 and adds 56 tests. Note that renamed tests count towards both.
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_dnd_Clipboard ‑ Unknown test
AllWin32Tests ImageWin32Tests ‑ testDisposeDrawnImageBeforeRequestingTargetForOtherZoom
AllWin32Tests ImageWin32Tests ‑ testDrawImageAtDifferentZooms(boolean)[1] true
AllWin32Tests ImageWin32Tests ‑ testDrawImageAtDifferentZooms(boolean)[2] false
AllWin32Tests ImageWin32Tests ‑ testImageDataForDifferentFractionalZoomsShouldBeDifferent
AllWin32Tests ImageWin32Tests ‑ testImageShouldHaveDimesionAsPerZoomLevel
AllWin32Tests ImageWin32Tests ‑ testRetrieveImageDataAtDifferentZooms(boolean)[1] true
AllWin32Tests ImageWin32Tests ‑ testRetrieveImageDataAtDifferentZooms(boolean)[2] false
AllWin32Tests ImageWin32Tests ‑ test_getImageData_fromCopiedImage
AllWin32Tests ImageWin32Tests ‑ test_getImageData_fromImageForImageDataFromImage
AllWin32Tests TestTreeColumn ‑ test_ColumnOrder
…

Copy link
Contributor

@akoch-yatta akoch-yatta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change is very simple and makes sense. Test failures are unrelated

@akoch-yatta akoch-yatta merged commit d10d7e4 into eclipse-platform:master Sep 26, 2025
15 of 17 checks passed
@akoch-yatta akoch-yatta deleted the fixNullPointerWhenDrawableNull branch September 26, 2025 15:06
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.

2 participants