Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bundles/org.eclipse.jface/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jface;singleton:=true
Bundle-Version: 3.38.100.qualifier
Bundle-Version: 3.39.0
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.jface,
Expand Down Expand Up @@ -34,7 +34,7 @@ Export-Package: org.eclipse.jface,
org.eclipse.jface.window,
org.eclipse.jface.wizard,
org.eclipse.jface.wizard.images
Require-Bundle: org.eclipse.swt;bundle-version="[3.126.0,4.0.0)";visibility:=reexport,
Require-Bundle: org.eclipse.swt;bundle-version="[3.132.0,3.134.0)";visibility:=reexport,
org.eclipse.core.commands;bundle-version="[3.4.0,4.0.0)";visibility:=reexport,
org.eclipse.equinox.common;bundle-version="[3.18.0,4.0.0)",
org.eclipse.equinox.bidi;bundle-version="[0.10.0,2.0.0)";resolution:=optional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.resource;

import java.net.URL;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.swt.graphics.Point;

class URLHintProvider implements Supplier<Point> {

private static final Pattern QUERY_PATTERN = Pattern.compile("&size=(\\d+)x(\\d+)"); //$NON-NLS-1$
private static final Pattern PATH_PATTERN = Pattern.compile("/(\\d+)x(\\d+)/"); //$NON-NLS-1$

private URL url;

public URLHintProvider(URL url) {
this.url = url;
}

@Override
public Point get() {
String query = url.getQuery();
Matcher matcher;
if (query != null && !query.isEmpty()) {
matcher = QUERY_PATTERN.matcher("&" + query); //$NON-NLS-1$
} else {
String path = url.getPath();
matcher = PATH_PATTERN.matcher(path);
}
if (matcher.find()) {
return new Point(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)));
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -42,6 +43,7 @@
import org.eclipse.swt.graphics.ImageDataProvider;
import org.eclipse.swt.graphics.ImageFileNameProvider;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.DPIUtil.ElementAtZoom;
import org.eclipse.swt.internal.NativeImageLoader;
import org.eclipse.swt.internal.image.FileFormat;
Expand Down Expand Up @@ -133,7 +135,7 @@
private static ImageData getImageData(URL url, int fileZoom, int targetZoom) {
try (InputStream in = getStream(url)) {
if (in != null) {
return loadImageFromStream(new BufferedInputStream(in), fileZoom, targetZoom);
return loadImageFromStream(new BufferedInputStream(in), fileZoom, targetZoom, new URLHintProvider(url));
}
} catch (SWTException e) {
if (e.code != SWT.ERROR_INVALID_IMAGE) {
Expand All @@ -146,8 +148,14 @@
return null;
}

@SuppressWarnings("restriction")

Check warning on line 151 in bundles/org.eclipse.jface/src/org/eclipse/jface/resource/URLImageDescriptor.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler

Unnecessary Code

NORMAL: Unnecessary @SuppressWarnings("restriction")
private static ImageData loadImageFromStream(InputStream stream, int fileZoom, int targetZoom) {
private static ImageData loadImageFromStream(InputStream stream, int fileZoom, int targetZoom,
Supplier<Point> hintProvider) {
Point hintSize = hintProvider.get();
if (hintSize != null) {
return NativeImageLoader.load(stream, new ImageLoader(), hintSize.x * targetZoom / fileZoom,
hintSize.y * targetZoom / fileZoom);
}
return NativeImageLoader.load(new ElementAtZoom<>(stream, fileZoom), new ImageLoader(), targetZoom).get(0)
.element();
}
Expand All @@ -171,6 +179,7 @@
}
return url.openStream();
} catch (IOException e) {
e.printStackTrace();
if (InternalPolicy.DEBUG_LOG_URL_IMAGE_DESCRIPTOR_MISSING_2x) {
String path = url.getPath();
if (path.endsWith("@2x.png") || path.endsWith("@1.5x.png")) { //$NON-NLS-1$ //$NON-NLS-2$
Expand Down
2 changes: 1 addition & 1 deletion examples/org.eclipse.jface.snippets/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="Eclipse JFace Snippets"/>
<classpathentry kind="output" path="bin"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
Expand Down Expand Up @@ -118,7 +118,7 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
org.eclipse.jdt.core.compiler.source=21
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*******************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.snippets.resources;

import java.net.URL;

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

/**
* A snippet to demonstrate SVG image size hints using path-based and
* query-parameter-based size detection.
*
* <p>
* This demonstrates two ways to control SVG rendering size:
* <ol>
* <li><b>Path-based hints:</b> Place SVG in folders like /icons/16x16/ or
* /icons/32x32/</li>
* <li><b>Query parameter hints:</b> Add ?size=WIDTHxHEIGHT to the URL</li>
* </ol>
* </p>
*
* <p>
* This allows using a single SVG file at different sizes without creating
* multiple scaled versions or restricting the SVG design size.
* </p>
*/
public class Snippet083SVGImageSizeHints {

public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("SVG Image Size Hints Demo");
GridLayoutFactory.fillDefaults().numColumns(2).margins(10, 10).spacing(10, 10).applyTo(shell);

addSection(shell, "Path-Based Size Hints", """
SVGs placed in folders with size patterns (e.g., /icons/16x16/, /icons/32x32/)
are automatically rendered at that size.
Example: bundle://plugin.id/icons/16x16/icon.svg
""");

addSection(shell, "Query Parameter Size Hints", """
You can specify size using query parameters for maximum flexibility.
This allows using the same SVG at different sizes.
Example: bundle://plugin.id/icons/icon.svg?size=16x16
Example: bundle://plugin.id/icons/icon.svg?size=128x128
""");

addSection(shell, "Zoom Support", """
Both methods work with high-DPI displays. The hint specifies the base size,
and JFace automatically scales for 150% and 200% zoom levels.
16x16 at 100% zoom → 16x16 pixels
16x16 at 150% zoom → 24x24 pixels
16x16 at 200% zoom → 32x32 pixels
""");

// Demonstrate with actual images from test resources if available
try {
URL svgUrl = Snippet083SVGImageSizeHints.class
.getResource("/org/eclipse/jface/snippets/resources/test-demo.svg");
if (svgUrl != null) {
addImageDemo(shell, "Default (no hint)", svgUrl.toString(), display);
addImageDemo(shell, "With ?size=32x32", svgUrl.toString() + "?size=32x32", display);
addImageDemo(shell, "With ?size=64x64", svgUrl.toString() + "?size=64x64", display);
}
} catch (Exception e) {
// Demo images not available, that's okay
Label note = new Label(shell, SWT.WRAP);
note.setText("Note: Visual demo requires test SVG files. See URLHintProviderTest for examples.");
GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(note);
}

addSection(shell, "Use Cases", """
1. Toolbar icons: Use ?size=16x16 for consistent toolbar sizing
2. Wizard images: Use ?size=128x128 for large wizard graphics
3. View icons: Place in /icons/16x16/ folder structure
4. Multi-resolution: One SVG serves all sizes without duplication
""");

addSection(shell, "Code Example", """
// Using query parameter
URL iconUrl = new URL("bundle://my.plugin/icons/search.svg?size=16x16");
ImageDescriptor desc = ImageDescriptor.createFromURL(iconUrl);
Image icon = desc.createImage();
// Using path-based hint
URL iconUrl = FileLocator.find(bundle, new Path("icons/16x16/search.svg"));
ImageDescriptor desc = ImageDescriptor.createFromURL(iconUrl);
""");

shell.pack();
shell.open();

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

private static void addSection(Shell shell, String title, String text) {
Label titleLabel = new Label(shell, SWT.BOLD);
titleLabel.setText(title);
GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(titleLabel);

Label textLabel = new Label(shell, SWT.WRAP);
textLabel.setText(text.trim());
GridDataFactory.fillDefaults().span(2, 1).grab(true, false).hint(600, SWT.DEFAULT).applyTo(textLabel);

Label separator = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(separator);
}

private static void addImageDemo(Shell shell, String description, String urlString, Display display) {
try {
URL url = new URL(urlString);

Check warning on line 138 in examples/org.eclipse.jface.snippets/Eclipse JFace Snippets/org/eclipse/jface/snippets/resources/Snippet083SVGImageSizeHints.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler

Deprecation

NORMAL: The constructor URL(String) is deprecated since version 20
ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
Image image = descriptor.createImage(display);

Label label = new Label(shell, SWT.NONE);
label.setText(description + ":");
GridDataFactory.fillDefaults().applyTo(label);

Canvas canvas = new Canvas(shell, SWT.BORDER);
canvas.addPaintListener(e -> {
if (!image.isDisposed()) {
e.gc.drawImage(image, 0, 0);
}
});
GridDataFactory.swtDefaults().hint(image.getBounds().width + 2, image.getBounds().height + 2)
.applyTo(canvas);

canvas.addDisposeListener(e -> {
if (!image.isDisposed()) {
image.dispose();
}
});
} catch (Exception e) {
Label error = new Label(shell, SWT.NONE);
error.setText(description + ": Error loading image");
GridDataFactory.fillDefaults().span(2, 1).applyTo(error);
}
}
}
2 changes: 1 addition & 1 deletion examples/org.eclipse.jface.snippets/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ Export-Package: org.eclipse.jface.snippets.dialogs,
org.eclipse.jface.snippets.viewers,
org.eclipse.jface.snippets.window,
org.eclipse.jface.snippets.wizard
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-RequiredExecutionEnvironment: JavaSE-21
Automatic-Module-Name: org.eclipse.jface.snippets
2 changes: 1 addition & 1 deletion tests/org.eclipse.jface.tests/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jface.tests
Bundle-Version: 1.4.1100.qualifier
Bundle-Version: 1.4.1200.qualifier
Automatic-Module-Name: org.eclipse.jface.tests
Bundle-RequiredExecutionEnvironment: JavaSE-17
Require-Bundle: org.junit;bundle-version="4.12.0",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions tests/org.eclipse.jface.tests/icons/imagetests/test-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

@Suite
@SelectClasses({ ImageRegistryTest.class, ResourceManagerTest.class, FileImageDescriptorTest.class,
UrlImageDescriptorTest.class, DecorationOverlayIconTest.class, DeferredImageDescriptorTest.class })
UrlImageDescriptorTest.class, URLHintProviderTest.class, DecorationOverlayIconTest.class,
DeferredImageDescriptorTest.class })
public class AllImagesTests {

public static void main(String[] args) {
Expand Down
Loading
Loading