This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 2b924c6f3f Fix Hop Web ClassNotFoundException for ImageDataProvider 
after #7955 (#7980)
2b924c6f3f is described below

commit 2b924c6f3f3f66c8328825a69a99865d5ae6479b
Author: Lance <[email protected]>
AuthorDate: Sun Aug 16 19:07:09 2026 +0800

    Fix Hop Web ClassNotFoundException for ImageDataProvider after #7955 (#7980)
    
    Signed-off-by: lance <[email protected]>
---
 .../org/apache/hop/core/SwtDesktopDpiImages.java   | 42 ++++++++++++++++++++++
 .../org/apache/hop/core/SwtUniversalImage.java     | 30 ++++++++++------
 .../org/apache/hop/core/SwtUniversalImageTest.java | 15 ++++++++
 3 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/ui/src/main/java/org/apache/hop/core/SwtDesktopDpiImages.java 
b/ui/src/main/java/org/apache/hop/core/SwtDesktopDpiImages.java
new file mode 100644
index 0000000000..157d5de718
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/core/SwtDesktopDpiImages.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.core;
+
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageDataProvider;
+
+/**
+ * Desktop SWT HiDPI image helpers. RAP/RWT does not ship {@link 
ImageDataProvider} or {@link
+ * Image#getImageData(int)}, so this class must never be loaded on Hop Web. 
Keep all references
+ * behind {@code SWT.getPlatform() != "rap"} in {@link SwtUniversalImage}.
+ */
+final class SwtDesktopDpiImages {
+
+  private SwtDesktopDpiImages() {}
+
+  static Image create(Device device, SwtUniversalImage.ImageDataAtZoom 
renderer) {
+    ImageDataProvider provider = renderer::render;
+    return new Image(device, provider);
+  }
+
+  static ImageData getImageData(Image image, int zoom) {
+    return image.getImageData(zoom);
+  }
+}
diff --git a/ui/src/main/java/org/apache/hop/core/SwtUniversalImage.java 
b/ui/src/main/java/org/apache/hop/core/SwtUniversalImage.java
index b57f419f30..e2804fe4fe 100644
--- a/ui/src/main/java/org/apache/hop/core/SwtUniversalImage.java
+++ b/ui/src/main/java/org/apache/hop/core/SwtUniversalImage.java
@@ -25,7 +25,6 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Device;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.ImageDataProvider;
 import org.eclipse.swt.graphics.PaletteData;
 import org.eclipse.swt.graphics.RGB;
 
@@ -121,9 +120,10 @@ public abstract class SwtUniversalImage {
 
   /**
    * SWT 3.134+ on Windows treats {@code new Image(device, ImageData)} as 100% 
zoom and
-   * raster-scales it to the monitor zoom (SMOOTH), which makes icons blurry 
at 200% DPI. {@link
-   * ImageDataProvider} re-rasterize at the requested zoom instead. RAP has no 
per-monitor zoom, so
-   * keep the ImageData constructor there.
+   * raster-scales it to the monitor zoom (SMOOTH), which makes icons blurry 
at 200% DPI. Desktop
+   * SWT re-rasterizes via ImageDataProvider instead. RAP has no per-monitor 
zoom and does not ship
+   * that type, so keep the ImageData constructor there and never link the 
desktop API from this
+   * class.
    */
   static boolean isDpiAwareImageProviderSupported() {
     return !"rap".equals(SWT.getPlatform());
@@ -131,7 +131,7 @@ public abstract class SwtUniversalImage {
 
   /**
    * Pixel size of a logical extent at an SWT zoom percentage. Must be linear 
({@code 200} → {@code
-   * 2 * 100}) to satisfy the {@link ImageDataProvider} contract.
+   * 2 * 100}) to satisfy the desktop ImageDataProvider contract.
    */
   static int pixelSize(int logical, int zoom) {
     return Math.max(1, logical * zoom / 100);
@@ -139,19 +139,20 @@ public abstract class SwtUniversalImage {
 
   /**
    * Creates an {@link Image} that can supply native pixels for every SWT 
zoom. On RAP the 100%
-   * variant is used as-is.
+   * variant is used as-is. The renderer type is Hop-owned so RAP class 
loading does not resolve
+   * desktop-only {@code org.eclipse.swt.graphics.ImageDataProvider}.
    */
-  public static Image createDpiAwareImage(Device device, ImageDataProvider 
provider) {
+  public static Image createDpiAwareImage(Device device, ImageDataAtZoom 
renderer) {
     if (!isDpiAwareImageProviderSupported()) {
-      return new Image(device, provider.getImageData(100));
+      return new Image(device, renderer.render(100));
     }
-    return new Image(device, provider);
+    return SwtDesktopDpiImages.create(device, renderer);
   }
 
   /** ImageData at the given zoom, with a RAP-safe fallback that scales the 
100% variant. */
   public static ImageData getImageDataAtZoom(Image image, int zoom) {
     if (isDpiAwareImageProviderSupported()) {
-      return image.getImageData(zoom);
+      return SwtDesktopDpiImages.getImageData(image, zoom);
     }
     ImageData data = image.getImageData();
     if (zoom == 100) {
@@ -190,6 +191,15 @@ public abstract class SwtUniversalImage {
     return new Image(device, toImageData(img));
   }
 
+  /**
+   * Supplies {@link ImageData} for an SWT zoom percentage (100, 150, 200, …). 
Same contract as
+   * desktop ImageDataProvider, without depending on that RAP-missing type.
+   */
+  @FunctionalInterface
+  public interface ImageDataAtZoom {
+    ImageData render(int zoom);
+  }
+
   @FunctionalInterface
   protected interface ImageDataAtSize {
     ImageData render(int width, int height);
diff --git a/ui/src/test/java/org/apache/hop/core/SwtUniversalImageTest.java 
b/ui/src/test/java/org/apache/hop/core/SwtUniversalImageTest.java
index 95f4f1ce8e..da2a413384 100644
--- a/ui/src/test/java/org/apache/hop/core/SwtUniversalImageTest.java
+++ b/ui/src/test/java/org/apache/hop/core/SwtUniversalImageTest.java
@@ -18,8 +18,11 @@
 package org.apache.hop.core;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 
 import java.awt.image.BufferedImage;
+import java.lang.reflect.Method;
+import org.eclipse.swt.graphics.Device;
 import org.eclipse.swt.graphics.ImageData;
 import org.junit.jupiter.api.Test;
 
@@ -44,4 +47,16 @@ class SwtUniversalImageTest {
     assertEquals(8, data.height);
     assertEquals(0x80, data.getAlpha(0, 0));
   }
+
+  @Test
+  void createDpiAwareImageSignatureDoesNotReferenceDesktopImageDataProvider() 
throws Exception {
+    Method method =
+        SwtUniversalImage.class.getMethod(
+            "createDpiAwareImage", Device.class, 
SwtUniversalImage.ImageDataAtZoom.class);
+    for (Class<?> type : method.getParameterTypes()) {
+      assertFalse(
+          type.getName().contains("ImageDataProvider"),
+          "RAP class loading resolves method signatures; keep 
ImageDataProvider off this API");
+    }
+  }
 }

Reply via email to