From 0ef8783c3f94274b0491c2df713ced6c7a242704 Mon Sep 17 00:00:00 2001 From: Michael Bangas Date: Mon, 16 Sep 2024 17:55:31 +0200 Subject: [PATCH] Add support for SVG images SWT currently loads icons exclusively as raster graphics (e.g., PNGs) without support for vector formats like SVG (except for Linux). A major drawback of raster graphics is their inability to scale without degrading image quality. Additionally, generating icons of different sizes requires manually rasterization of SVGs as a preparatory step, leading to unnecessary effort and many icon files. This change introduces support for vector graphics in images, enabling SVGs to be used for images. An SVG rasterizer can be provided via an SWT fragment. This change adds an according fragment based on the JSVG library. An according FileFormat implementation is added, which utilized a present SVG rasterization fragment to rasterize images for the desired zoom factor. Fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/1438 --- bundles/org.eclipse.swt.svg/.classpath | 7 + bundles/org.eclipse.swt.svg/.project | 28 +++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 10 + .../org.eclipse.swt.svg/META-INF/MANIFEST.MF | 13 + ...g.eclipse.swt.internal.image.SVGRasterizer | 1 + bundles/org.eclipse.swt.svg/build.properties | 15 ++ .../org.eclipse.swt.svg/fragment.properties | 14 ++ .../org/eclipse/swt/svg/JSVGRasterizer.java | 136 +++++++++++ .../common/org/eclipse/swt/SWT.java | 1 - .../swt/internal/image/FileFormat.java | 3 + .../swt/internal/image/SVGFileFormat.java | 66 ++++++ .../swt/internal/image/SVGRasterizer.java | 35 +++ .../swt/tests/junit/AllNonBrowserTests.java | 1 + ...rg_eclipse_swt_internal_SVGRasterizer.java | 95 ++++++++ tests/org.eclipse.swt.tests/META-INF/p2.inf | 4 + .../data/collapseall.svg | 223 ++++++++++++++++++ tests/org.eclipse.swt.tests/data/corrupt.svg | 210 +++++++++++++++++ 18 files changed, 863 insertions(+), 1 deletion(-) create mode 100644 bundles/org.eclipse.swt.svg/.classpath create mode 100644 bundles/org.eclipse.swt.svg/.project create mode 100644 bundles/org.eclipse.swt.svg/.settings/org.eclipse.core.resources.prefs create mode 100644 bundles/org.eclipse.swt.svg/.settings/org.eclipse.jdt.core.prefs create mode 100644 bundles/org.eclipse.swt.svg/META-INF/MANIFEST.MF create mode 100644 bundles/org.eclipse.swt.svg/META-INF/services/org.eclipse.swt.internal.image.SVGRasterizer create mode 100644 bundles/org.eclipse.swt.svg/build.properties create mode 100644 bundles/org.eclipse.swt.svg/fragment.properties create mode 100644 bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java create mode 100644 tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_internal_SVGRasterizer.java create mode 100644 tests/org.eclipse.swt.tests/META-INF/p2.inf create mode 100644 tests/org.eclipse.swt.tests/data/collapseall.svg create mode 100644 tests/org.eclipse.swt.tests/data/corrupt.svg diff --git a/bundles/org.eclipse.swt.svg/.classpath b/bundles/org.eclipse.swt.svg/.classpath new file mode 100644 index 00000000000..81fe078c20c --- /dev/null +++ b/bundles/org.eclipse.swt.svg/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.eclipse.swt.svg/.project b/bundles/org.eclipse.swt.svg/.project new file mode 100644 index 00000000000..587ce542c7c --- /dev/null +++ b/bundles/org.eclipse.swt.svg/.project @@ -0,0 +1,28 @@ + + + org.eclipse.swt.svg + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.eclipse.swt.svg/.settings/org.eclipse.core.resources.prefs b/bundles/org.eclipse.swt.svg/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/bundles/org.eclipse.swt.svg/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/bundles/org.eclipse.swt.svg/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.swt.svg/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..4b76983c5f1 --- /dev/null +++ b/bundles/org.eclipse.swt.svg/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.incompleteClasspath=warning diff --git a/bundles/org.eclipse.swt.svg/META-INF/MANIFEST.MF b/bundles/org.eclipse.swt.svg/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..d65dc50cfdf --- /dev/null +++ b/bundles/org.eclipse.swt.svg/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-SymbolicName: org.eclipse.swt.svg +Bundle-Version: 3.130.0.qualifier +Automatic-Module-Name: org.eclipse.swt.svg +Bundle-Name: %fragmentName +Bundle-Vendor: %providerName +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Fragment-Host: org.eclipse.swt +Import-Package: com.github.weisj.jsvg;version="[1.7.0,2.0.0)", + com.github.weisj.jsvg.geometry.size;version="[1.7.0,2.0.0)", + com.github.weisj.jsvg.parser;version="[1.7.0,2.0.0)" +Export-Package: org.eclipse.swt.svg diff --git a/bundles/org.eclipse.swt.svg/META-INF/services/org.eclipse.swt.internal.image.SVGRasterizer b/bundles/org.eclipse.swt.svg/META-INF/services/org.eclipse.swt.internal.image.SVGRasterizer new file mode 100644 index 00000000000..bd95b6eea89 --- /dev/null +++ b/bundles/org.eclipse.swt.svg/META-INF/services/org.eclipse.swt.internal.image.SVGRasterizer @@ -0,0 +1 @@ +org.eclipse.swt.svg.JSVGRasterizer diff --git a/bundles/org.eclipse.swt.svg/build.properties b/bundles/org.eclipse.swt.svg/build.properties new file mode 100644 index 00000000000..bfdbd565a5b --- /dev/null +++ b/bundles/org.eclipse.swt.svg/build.properties @@ -0,0 +1,15 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + fragment.properties + +tycho.pomless.parent = ../../local-build/local-build-parent +jars.extra.classpath = platform:/plugin/org.eclipse.swt.cocoa.macosx.aarch64,\ + platform:/plugin/org.eclipse.swt.cocoa.macosx.x86_64,\ + platform:/plugin/org.eclipse.swt.gtk.linux.aarch64,\ + platform:/plugin/org.eclipse.swt.gtk.linux.ppc64le,\ + platform:/plugin/org.eclipse.swt.gtk.linux.riscv64,\ + platform:/plugin/org.eclipse.swt.gtk.linux.x86_64,\ + platform:/plugin/org.eclipse.swt.win32.win32.aarch64,\ + platform:/plugin/org.eclipse.swt.win32.win32.x86_64 diff --git a/bundles/org.eclipse.swt.svg/fragment.properties b/bundles/org.eclipse.swt.svg/fragment.properties new file mode 100644 index 00000000000..1ae8d5b50da --- /dev/null +++ b/bundles/org.eclipse.swt.svg/fragment.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2025 Vector Informatik GmbH 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: +# Michael Bangas (Vector Informatik GmbH) - initial API and implementation +############################################################################### +fragmentName = SWT SVG Rendering Support +providerName = Eclipse.org diff --git a/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java b/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java new file mode 100644 index 00000000000..0da0c7872dc --- /dev/null +++ b/bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2025 Vector Informatik GmbH 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: + * Michael Bangas (Vector Informatik GmbH) - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.svg; + +import static java.awt.RenderingHints.KEY_ALPHA_INTERPOLATION; +import static java.awt.RenderingHints.KEY_ANTIALIASING; +import static java.awt.RenderingHints.KEY_COLOR_RENDERING; +import static java.awt.RenderingHints.KEY_DITHERING; +import static java.awt.RenderingHints.KEY_FRACTIONALMETRICS; +import static java.awt.RenderingHints.KEY_INTERPOLATION; +import static java.awt.RenderingHints.KEY_RENDERING; +import static java.awt.RenderingHints.KEY_STROKE_CONTROL; +import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING; +import static java.awt.RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY; +import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON; +import static java.awt.RenderingHints.VALUE_COLOR_RENDER_QUALITY; +import static java.awt.RenderingHints.VALUE_DITHER_DISABLE; +import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON; +import static java.awt.RenderingHints.VALUE_INTERPOLATION_BICUBIC; +import static java.awt.RenderingHints.VALUE_RENDER_QUALITY; +import static java.awt.RenderingHints.VALUE_STROKE_PURE; +import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON; + +import java.awt.Graphics2D; +import java.awt.RenderingHints.Key; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.internal.image.SVGRasterizer; + +import com.github.weisj.jsvg.SVGDocument; +import com.github.weisj.jsvg.geometry.size.FloatSize; +import com.github.weisj.jsvg.parser.LoaderContext; +import com.github.weisj.jsvg.parser.SVGLoader; + +/** + * A rasterizer implementation for converting SVG data into rasterized images. + * This class uses the third party library JSVG for the raterization of SVG + * images. + */ +public class JSVGRasterizer implements SVGRasterizer { + + private static final SVGLoader SVG_LOADER = new SVGLoader(); + + private final static Map RENDERING_HINTS = Map.of( // + KEY_ANTIALIASING, VALUE_ANTIALIAS_ON, // + KEY_ALPHA_INTERPOLATION, VALUE_ALPHA_INTERPOLATION_QUALITY, // + KEY_COLOR_RENDERING, VALUE_COLOR_RENDER_QUALITY, // + KEY_DITHERING, VALUE_DITHER_DISABLE, // + KEY_FRACTIONALMETRICS, VALUE_FRACTIONALMETRICS_ON, // + KEY_INTERPOLATION, VALUE_INTERPOLATION_BICUBIC, // + KEY_RENDERING, VALUE_RENDER_QUALITY, // + KEY_STROKE_CONTROL, VALUE_STROKE_PURE, // + KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON // + ); + + @Override + public ImageData rasterizeSVG(InputStream inputStream, int zoom) throws IOException { + SVGDocument svgDocument = loadSVG(inputStream); + if (svgDocument == null) { + SWT.error(SWT.ERROR_INVALID_IMAGE); + } + BufferedImage rasterizedImage = renderSVG(svgDocument, zoom); + return convertToSWTImageData(rasterizedImage); + } + + private SVGDocument loadSVG(InputStream inputStream) { + return SVG_LOADER.load(inputStream, null, LoaderContext.createDefault()); + } + + private BufferedImage renderSVG(SVGDocument svgDocument, int zoom) { + float scalingFactor = zoom / 100.0f; + BufferedImage image = createImageBase(svgDocument, scalingFactor); + Graphics2D g = configureRenderingOptions(scalingFactor, image); + svgDocument.render(null, g); + g.dispose(); + return image; + } + + private BufferedImage createImageBase(SVGDocument svgDocument, float scalingFactor) { + FloatSize sourceImageSize = svgDocument.size(); + int targetImageWidth = calculateTargetWidth(scalingFactor, sourceImageSize); + int targetImageHeight = calculateTargetHeight(scalingFactor, sourceImageSize); + return new BufferedImage(targetImageWidth, targetImageHeight, BufferedImage.TYPE_INT_ARGB); + } + + private int calculateTargetWidth(float scalingFactor, FloatSize sourceImageSize) { + double sourceImageWidth = sourceImageSize.getWidth(); + return (int) Math.round(sourceImageWidth * scalingFactor); + } + + private int calculateTargetHeight(float scalingFactor, FloatSize sourceImageSize) { + double sourceImageHeight = sourceImageSize.getHeight(); + return (int) Math.round(sourceImageHeight * scalingFactor); + } + + private Graphics2D configureRenderingOptions(float scalingFactor, BufferedImage image) { + Graphics2D g = image.createGraphics(); + g.setRenderingHints(RENDERING_HINTS); + g.scale(scalingFactor, scalingFactor); + return g; + } + + private ImageData convertToSWTImageData(BufferedImage rasterizedImage) { + int width = rasterizedImage.getWidth(); + int height = rasterizedImage.getHeight(); + int[] pixels = ((DataBufferInt) rasterizedImage.getRaster().getDataBuffer()).getData(); + PaletteData paletteData = new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF); + ImageData imageData = new ImageData(width, height, 32, paletteData); + int index = 0; + for (int y = 0; y < imageData.height; y++) { + for (int x = 0; x < imageData.width; x++) { + int alpha = (pixels[index] >> 24) & 0xFF; + imageData.setAlpha(x, y, alpha); + imageData.setPixel(x, y, pixels[index++]); + } + } + return imageData; + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java index 010e828d1d8..db336185913 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java @@ -4465,7 +4465,6 @@ public class SWT { /** * Image format constant indicating a SVG format image (value is 8). - *
Note that this is a HINT and is currently only supported on GTK. * * @since 3.113 */ diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java index ea524de8fd0..fd9c89a8347 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java @@ -53,6 +53,9 @@ public abstract class FileFormat { try { FORMAT_FACTORIES.add(OS2BMPFileFormat::new); } catch (NoClassDefFoundError e) { } // ignore format + try { + FORMAT_FACTORIES.add(SVGFileFormat::new); + } catch (NoClassDefFoundError e) { } // ignore format } public static final int DEFAULT_ZOOM = 100; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java new file mode 100644 index 00000000000..001b9b6828d --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGFileFormat.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2025 Vector Informatik GmbH 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: + * Michael Bangas (Vector Informatik GmbH) - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.image; + +import java.io.*; +import java.nio.charset.*; +import java.util.*; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.DPIUtil.*; + +/** + * A {@link FileFormat} implementation for handling SVG (Scalable Vector + * Graphics) files. + *

+ * This class detects SVG files based on their header and uses a registered + * {@link SVGRasterizer} service to rasterize SVG content. + *

+ */ +public class SVGFileFormat extends FileFormat { + + /** The instance of the registered {@link SVGRasterizer}. */ + private static final SVGRasterizer RASTERIZER = ServiceLoader.load(SVGRasterizer.class).findFirst().orElse(null); + + @Override + boolean isFileFormat(LEDataInputStream stream) throws IOException { + byte[] firstBytes = new byte[5]; + int bytesRead = stream.read(firstBytes); + stream.unread(firstBytes); + String header = new String(firstBytes, 0, bytesRead, StandardCharsets.UTF_8).trim(); + return header.startsWith("> loadFromByteStream(int fileZoom, int targetZoom) { + if (RASTERIZER == null) { + SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT, null, " [No SVG rasterizer found]"); + } + if (targetZoom <= 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " [Cannot rasterize SVG for zoom <= 0]"); + } + try { + ImageData rasterizedImageData = RASTERIZER.rasterizeSVG(inputStream, 100 * targetZoom / fileZoom); + return List.of(new ElementAtZoom<>(rasterizedImageData, targetZoom)); + } catch (IOException e) { + SWT.error(SWT.ERROR_INVALID_IMAGE, e); + return List.of(); + } + } + + @Override + void unloadIntoByteStream(ImageLoader loader) { + throw new UnsupportedOperationException(); + } +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java new file mode 100644 index 00000000000..9586abfb5c6 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2025 Vector Informatik GmbH 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: + * Michael Bangas (Vector Informatik GmbH) - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.image; + +import java.io.*; + +import org.eclipse.swt.graphics.*; + +/** + * Defines the interface for an SVG rasterizer, responsible for converting SVG + * data into rasterized images. + */ +public interface SVGRasterizer { + /** + * Rasterizes an SVG image from the provided {@code InputStream} using the + * specified zoom. + * + * @param stream the SVG image as an {@link InputStream}. + * @param zoom the scaling factor (in percent) e.g. {@code 200} for doubled + * size. This value must be greater zero. + * @return the {@link ImageData} for the rasterized image, or {@code null} if + * the input is not a valid SVG file or cannot be processed. + */ + public ImageData rasterizeSVG(InputStream stream, int zoom) throws IOException; +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/AllNonBrowserTests.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/AllNonBrowserTests.java index af9a1bd017d..2f5ae54445e 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/AllNonBrowserTests.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/AllNonBrowserTests.java @@ -45,6 +45,7 @@ Test_org_eclipse_swt_accessibility_AccessibleControlEvent.class, Test_org_eclipse_swt_accessibility_AccessibleEvent.class, Test_org_eclipse_swt_accessibility_AccessibleTextEvent.class, + Test_org_eclipse_swt_internal_SVGRasterizer.class, DPIUtilTests.class}) public class AllNonBrowserTests { private static List leakedResources; diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_internal_SVGRasterizer.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_internal_SVGRasterizer.java new file mode 100644 index 00000000000..32a02163727 --- /dev/null +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_internal_SVGRasterizer.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2025 Vector Informatik GmbH 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: + * Michael Bangas (Vector Informatik GmbH) - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.junit; + +import static org.eclipse.swt.tests.junit.SwtTestUtil.assertSWTProblem; +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageDataProvider; +import org.eclipse.swt.graphics.ImageFileNameProvider; +import org.eclipse.swt.widgets.Display; +import org.junit.Test; + +/** + * When executed locally (outside Tycho build), this tests needs to be run as + * JUnit plug-in test in order to have the SVGRasterizer fragment on the + * classpath. + */ +public class Test_org_eclipse_swt_internal_SVGRasterizer { + + @Test + public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageFileNameProvider() { + ImageFileNameProvider validImageFileNameProvider = zoom -> getPath("collapseall.svg"); + Image image = new Image(Display.getDefault(), validImageFileNameProvider); + image.dispose(); + + ImageFileNameProvider corruptImageFileNameProvider = zoom -> getPath("corrupt.svg"); + SWTException e = assertThrows(SWTException.class, + () -> new Image(Display.getDefault(), corruptImageFileNameProvider)); + assertSWTProblem("Incorrect exception thrown for provider with corrupt images", SWT.ERROR_INVALID_IMAGE, e); + } + + @Test + public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageDataProvider() { + ImageDataProvider validImageDataProvider = zoom -> { + String fileName = "collapseall.svg"; + return new ImageData(getPath(fileName)); + }; + Image image = new Image(Display.getDefault(), validImageDataProvider); + image.dispose(); + + ImageDataProvider corruptImageDataProvider = zoom -> { + String fileName = "corrupt.svg"; + return new ImageData(getPath(fileName)); + }; + SWTException e = assertThrows(SWTException.class, + () -> new Image(Display.getDefault(), corruptImageDataProvider)); + assertSWTProblem("Incorrect exception thrown for provider with corrupt images", SWT.ERROR_INVALID_IMAGE, e); + } + + String getPath(String fileName) { + String urlPath = ""; + String pluginPath = System.getProperty("PLUGIN_PATH"); + if (pluginPath == null) { + URL url = getClass().getClassLoader().getResource(fileName); + if (url == null) { + fail("URL == null for file " + fileName); + } + urlPath = url.getFile(); + } else { + urlPath = pluginPath + "/data/" + fileName; + } + if (File.separatorChar != '/') + urlPath = urlPath.replace('/', File.separatorChar); + if (SwtTestUtil.isWindows && urlPath.indexOf(File.separatorChar) == 0) + urlPath = urlPath.substring(1); + urlPath = urlPath.replaceAll("%20", " "); + // Fallback when test is locally executed as plug-in test + if (!Files.exists(Path.of(urlPath))) { + urlPath = Path.of("data/" + fileName).toAbsolutePath().toString(); + } + assertTrue(Files.exists(Path.of(urlPath)), "file not found: " + urlPath); + return urlPath; + } +} \ No newline at end of file diff --git a/tests/org.eclipse.swt.tests/META-INF/p2.inf b/tests/org.eclipse.swt.tests/META-INF/p2.inf new file mode 100644 index 00000000000..d63e5216db8 --- /dev/null +++ b/tests/org.eclipse.swt.tests/META-INF/p2.inf @@ -0,0 +1,4 @@ +# pull in the applicable implementation fragment at build time (bug 461427) +requires.0.namespace = org.eclipse.equinox.p2.iu +requires.0.name = org.eclipse.swt.svg +requires.0.range = 0.0.0 diff --git a/tests/org.eclipse.swt.tests/data/collapseall.svg b/tests/org.eclipse.swt.tests/data/collapseall.svg new file mode 100644 index 00000000000..587c3c3497e --- /dev/null +++ b/tests/org.eclipse.swt.tests/data/collapseall.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/tests/org.eclipse.swt.tests/data/corrupt.svg b/tests/org.eclipse.swt.tests/data/corrupt.svg new file mode 100644 index 00000000000..edac6e7e9f2 --- /dev/null +++ b/tests/org.eclipse.swt.tests/data/corrupt.svg @@ -0,0 +1,210 @@ + + + +< inkscape:version="0.91 r13725" + sodipodi:docname="collapseall.svg"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + +