Skip to content

Commit ea6eb49

Browse files
committed
disabled icon logic
cleanup
1 parent 682e9ab commit ea6eb49

File tree

7 files changed

+277
-3
lines changed

7 files changed

+277
-3
lines changed

binaries/org.eclipse.swt.win32.win32.x86_64/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Fragment-Host: org.eclipse.swt;bundle-version="[3.128.0,4.0.0)"
33
Bundle-Name: %fragmentName
44
Bundle-Vendor: %providerName
55
Bundle-SymbolicName: org.eclipse.swt.win32.win32.x86_64; singleton:=true
6-
Bundle-Version: 3.130.0.qualifier
6+
Bundle-Version: 4.0.0.qualifier
77
Bundle-ManifestVersion: 2
88
Bundle-Localization: fragment
99
Export-Package:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Vector Informatik GmbH and others.
3+
*
4+
* This program and the accompanying materials are made available under the terms of the Eclipse
5+
* Public License 2.0 which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors: Michael Bangas (Vector Informatik GmbH) - initial API and implementation
11+
*******************************************************************************/
12+
package org.eclipse.swt.svg.tests.junit;
13+
14+
import static org.eclipse.swt.tests.junit.SwtTestUtil.assertSWTProblem;
15+
import static org.junit.Assert.fail;
16+
17+
import java.io.File;
18+
import java.nio.file.Path;
19+
import org.eclipse.swt.SWT;
20+
import org.eclipse.swt.SWTException;
21+
import org.eclipse.swt.graphics.Image;
22+
import org.eclipse.swt.graphics.ImageData;
23+
import org.eclipse.swt.graphics.ImageDataProvider;
24+
import org.eclipse.swt.graphics.ImageFileNameProvider;
25+
import org.eclipse.swt.tests.junit.SwtTestUtil;
26+
import org.eclipse.swt.widgets.Display;
27+
import org.junit.Before;
28+
import org.junit.Test;
29+
30+
public class Test_org_eclipse_swt_internal_SVGRasterizer {
31+
32+
Display display;
33+
34+
ImageFileNameProvider imageFileNameProvider = zoom -> {
35+
String fileName = "collapseall.svg";
36+
return getPath(fileName);
37+
};
38+
39+
ImageDataProvider imageDataProvider = zoom -> {
40+
String fileName = "collapseall.svg";
41+
return new ImageData(getPath(fileName), zoom, SWT.IMAGE_COPY);
42+
};
43+
44+
@Before
45+
public void setUp() {
46+
display = Display.getDefault();
47+
}
48+
49+
String getPath(String fileName) {
50+
String urlPath = "";
51+
String pluginPath = System.getProperty("PLUGIN_PATH");
52+
if (pluginPath == null) {
53+
urlPath = Path.of("data/" + fileName).toAbsolutePath().toString();
54+
} else {
55+
urlPath = pluginPath + "/data/" + fileName;
56+
}
57+
if (File.separatorChar != '/')
58+
urlPath = urlPath.replace('/', File.separatorChar);
59+
if (SwtTestUtil.isWindows && urlPath.indexOf(File.separatorChar) == 0)
60+
urlPath = urlPath.substring(1);
61+
urlPath = urlPath.replaceAll("%20", " ");
62+
return urlPath;
63+
}
64+
65+
@Test
66+
public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageFileNameProvider() {
67+
// Valid provider
68+
Image image = new Image(display, imageFileNameProvider);
69+
image.dispose();
70+
// Corrupt Image provider
71+
ImageFileNameProvider provider = zoom -> {
72+
String fileName = "corrupt.svg";
73+
return getPath(fileName);
74+
};
75+
try {
76+
image = new Image(display, provider);
77+
image.dispose();
78+
fail("No exception thrown for corrupt image file.");
79+
} catch (SWTException e) {
80+
assertSWTProblem("Incorrect exception thrown for provider with corrupt images", SWT.ERROR_INVALID_IMAGE, e);
81+
}
82+
}
83+
84+
@Test
85+
public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageDataProvider() {
86+
// Valid provider
87+
Image image = new Image(display, imageDataProvider);
88+
image.dispose();
89+
// Corrupt Image provider
90+
ImageDataProvider provider = zoom -> {
91+
String fileName = "corrupt.svg";
92+
return new ImageData(getPath(fileName), zoom, SWT.IMAGE_COPY);
93+
};
94+
try {
95+
image = new Image(display, provider);
96+
image.dispose();
97+
fail("No exception thrown for corrupt image file.");
98+
} catch (SWTException e) {
99+
assertSWTProblem("Incorrect exception thrown for provider with corrupt images", SWT.ERROR_INVALID_IMAGE, e);
100+
}
101+
}
102+
}

bundles/org.eclipse.swt.svg/src/org/eclipse/swt/svg/JSVGRasterizer.java

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,30 @@
3535
import java.awt.RenderingHints.Key;
3636
import java.awt.image.BufferedImage;
3737
import java.awt.image.DataBufferInt;
38+
import java.io.ByteArrayInputStream;
39+
import java.io.ByteArrayOutputStream;
3840
import java.io.IOException;
3941
import java.io.InputStream;
42+
import java.io.OutputStream;
4043
import java.util.Map;
4144

4245
import org.eclipse.swt.SWT;
4346
import org.eclipse.swt.graphics.ImageData;
4447
import org.eclipse.swt.graphics.PaletteData;
4548
import org.eclipse.swt.internal.image.SVGRasterizer;
4649

50+
import javax.xml.parsers.DocumentBuilder;
51+
import javax.xml.parsers.DocumentBuilderFactory;
52+
import javax.xml.parsers.ParserConfigurationException;
53+
import javax.xml.transform.Transformer;
54+
import javax.xml.transform.TransformerException;
55+
import javax.xml.transform.TransformerFactory;
56+
import javax.xml.transform.dom.DOMSource;
57+
import javax.xml.transform.stream.StreamResult;
58+
import org.w3c.dom.Document;
59+
import org.w3c.dom.Element;
60+
import org.xml.sax.SAXException;
61+
4762
import com.github.weisj.jsvg.SVGDocument;
4863
import com.github.weisj.jsvg.geometry.size.FloatSize;
4964
import com.github.weisj.jsvg.parser.LoaderContext;
@@ -73,7 +88,19 @@ public class JSVGRasterizer implements SVGRasterizer {
7388
);
7489

7590
@Override
76-
public ImageData[] rasterizeSVG(InputStream inputStream, int zoom) throws IOException {
91+
public ImageData[] rasterizeSVG(InputStream inputStream, int zoom, int flag) throws IOException {
92+
switch(flag) {
93+
case SWT.IMAGE_DISABLE:
94+
inputStream = applyDisabledLook(inputStream);
95+
break;
96+
case SWT.IMAGE_GRAY:
97+
inputStream = applyGrayLook(inputStream);
98+
break;
99+
case SWT.IMAGE_COPY:
100+
break;
101+
default:
102+
SWT.error(SWT.ERROR_INVALID_IMAGE);
103+
}
77104
SVGDocument svgDocument = loadSVG(inputStream);
78105
if (svgDocument != null) {
79106
return generateRasterizedImageData(svgDocument, zoom);
@@ -141,4 +168,80 @@ private ImageData[] convertToSWTImageData(BufferedImage rasterizedImage) {
141168
}
142169
return new ImageData[]{imageData};
143170
}
171+
172+
private static InputStream applyDisabledLook(InputStream svgInputStream) throws IOException {
173+
Document svgDocument = parseSVG(svgInputStream);
174+
addDisabledFilter(svgDocument);
175+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
176+
writeSVG(svgDocument, outputStream);
177+
return new ByteArrayInputStream(outputStream.toByteArray());
178+
}
179+
}
180+
181+
private static InputStream applyGrayLook(InputStream svgInputStream) throws IOException {
182+
Document svgDocument = parseSVG(svgInputStream);
183+
addGrayFilter(svgDocument);
184+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
185+
writeSVG(svgDocument, outputStream);
186+
return new ByteArrayInputStream(outputStream.toByteArray());
187+
}
188+
}
189+
190+
private static Document parseSVG(InputStream inputStream) throws IOException {
191+
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
192+
DocumentBuilder builder;
193+
try {
194+
builder = factory.newDocumentBuilder();
195+
return builder.parse(inputStream);
196+
} catch (SAXException | IOException | ParserConfigurationException e) {
197+
throw new IOException(e.getMessage());
198+
}
199+
}
200+
201+
private static void addDisabledFilter(Document document) {
202+
addFilter(document, 0.64f, 0.4f);
203+
}
204+
205+
private static void addGrayFilter(Document document) {
206+
addFilter(document, 0.64f, 0.1f);
207+
}
208+
209+
private static void addFilter(Document document, float slope, float intercept) {
210+
Element defs = (Element) document.getElementsByTagName("defs").item(0);
211+
if (defs == null) {
212+
defs = document.createElement("defs");
213+
document.getDocumentElement().appendChild(defs);
214+
}
215+
216+
Element filter = document.createElement("filter");
217+
filter.setAttribute("id", "customizedLook");
218+
219+
Element colorMatrix = document.createElement("feColorMatrix");
220+
colorMatrix.setAttribute("type", "saturate");
221+
colorMatrix.setAttribute("values", "0");
222+
filter.appendChild(colorMatrix);
223+
224+
Element componentTransfer = document.createElement("feComponentTransfer");
225+
for (String channel : new String[] { "R", "G", "B" }) {
226+
Element func = document.createElement("feFunc" + channel);
227+
func.setAttribute("type", "linear");
228+
func.setAttribute("slope", Float.toString(slope));
229+
func.setAttribute("intercept", Float.toString(intercept));
230+
componentTransfer.appendChild(func);
231+
}
232+
filter.appendChild(componentTransfer);
233+
defs.appendChild(filter);
234+
document.getDocumentElement().setAttribute("filter", "url(#customizedLook)");
235+
}
236+
237+
private static void writeSVG(Document document, OutputStream outputStream) throws IOException {
238+
TransformerFactory transformerFactory = TransformerFactory.newInstance();
239+
Transformer transformer;
240+
try {
241+
transformer = transformerFactory.newTransformer();
242+
transformer.transform(new DOMSource(document), new StreamResult(outputStream));
243+
} catch (TransformerException e) {
244+
throw new IOException(e.getMessage());
245+
}
246+
}
144247
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataProvider.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,17 @@ public interface ImageDataProvider {
4343
*/
4444
ImageData getImageData (int zoom);
4545

46+
/**
47+
* @since 4.0
48+
*/
49+
default ImageData getCustomizedImageData(int zoom, int flag) {
50+
throw new UnsupportedOperationException();
51+
}
52+
53+
/**
54+
* @since 4.0
55+
*/
56+
default boolean supportsRasterizationFlag(int flag) {
57+
return false;
58+
}
4659
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ List<ElementAtZoom<ImageData>> load(InputStream stream, int fileZoom, int target
162162
return images;
163163
}
164164

165+
//TODO: JavaDocs flag parameter
165166
/**
166167
* Loads an array of <code>ImageData</code> objects from the
167168
* file with the specified name. Throws an error if either

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/SVGRasterizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ public interface SVGRasterizer {
3434
* the input is not a valid SVG file or cannot be processed.
3535
* @throws IOException
3636
*/
37-
public ImageData[] rasterizeSVG(InputStream stream, int zoom) throws IOException;
37+
public ImageData[] rasterizeSVG(InputStream stream, int zoom, int flag) throws IOException;
3838
}

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ public Image(Device device, Image srcImage, int flag) {
239239
long srcImageHandle = win32_getHandle(srcImage, getZoom());
240240
switch (flag) {
241241
case SWT.IMAGE_COPY: {
242+
if(createWithSVG(device, flag)) {
243+
break;
244+
}
242245
switch (type) {
243246
case SWT.BITMAP:
244247
/* Get the HDC for the device */
@@ -274,12 +277,18 @@ public Image(Device device, Image srcImage, int flag) {
274277
break;
275278
}
276279
case SWT.IMAGE_DISABLE: {
280+
if(createWithSVG(device, flag)) {
281+
break;
282+
}
277283
ImageData data = srcImage.getImageData(srcImage.getZoom());
278284
ImageData newData = applyDisableImageData(data, rect.height, rect.width);
279285
init (newData, getZoom());
280286
break;
281287
}
282288
case SWT.IMAGE_GRAY: {
289+
if(createWithSVG(device, flag)) {
290+
break;
291+
}
283292
ImageData data = srcImage.getImageData(srcImage.getZoom());
284293
ImageData newData = applyGrayImageData(data, rect.height, rect.width);
285294
init (newData, getZoom());
@@ -292,6 +301,28 @@ public Image(Device device, Image srcImage, int flag) {
292301
this.device.registerResourceWithZoomSupport(this);
293302
}
294303

304+
private boolean createWithSVG(Device device, int flag) {
305+
ImageData data = null;
306+
Image customizedImage = null;
307+
if (imageProvider.getProvider() instanceof ImageFileNameProvider imageFileNameProvider) {
308+
ElementAtZoom<String> fileName = DPIUtil.validateAndGetImagePathAtZoom(imageFileNameProvider, getZoom());
309+
if (fileName.element().endsWith(".svg")) {
310+
customizedImage = new Image(device, imageFileNameProvider, flag);
311+
}
312+
} else if (imageProvider.getProvider() instanceof ImageDataProvider imageDataProvider) {
313+
if (imageDataProvider.supportsRasterizationFlag(flag)) {
314+
customizedImage = new Image(device, imageDataProvider, flag);
315+
}
316+
}
317+
if(customizedImage != null) {
318+
data = customizedImage.getImageData(customizedImage.getZoom());
319+
init(data, getZoom());
320+
customizedImage.dispose();
321+
return true;
322+
}
323+
return false;
324+
}
325+
295326
/**
296327
* Constructs an empty instance of this class with the
297328
* width and height of the specified rectangle. The result
@@ -561,6 +592,20 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) {
561592
this.device.registerResourceWithZoomSupport(this);
562593
}
563594

595+
private Image(Device device, ImageFileNameProvider imageFileNameProvider, int flag) {
596+
super(device);
597+
this.imageProvider = new ImageFileNameProviderWrapper(imageFileNameProvider);
598+
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
599+
int zoom = getZoom();
600+
ElementAtZoom<String> fileName = DPIUtil.validateAndGetImagePathAtZoom (imageFileNameProvider, zoom);
601+
ImageHandle imageMetadata = initNative (fileName.element(), zoom);
602+
if (imageMetadata == null) {
603+
init(new ImageData (fileName.element(), zoom, flag), zoom);
604+
}
605+
init();
606+
this.device.registerResourceWithZoomSupport(this);
607+
}
608+
564609
/**
565610
* Constructs an instance of this class by loading its representation
566611
* from the ImageData retrieved from the ImageDataProvider. Throws an
@@ -599,6 +644,16 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
599644
this.device.registerResourceWithZoomSupport(this);
600645
}
601646

647+
private Image(Device device, ImageDataProvider imageDataProvider, int flag) {
648+
super(device);
649+
this.imageProvider = new ImageDataProviderWrapper(imageDataProvider);
650+
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
651+
ImageData data = imageDataProvider.getCustomizedImageData(getZoom(), flag);
652+
init (data, getZoom());
653+
init();
654+
this.device.registerResourceWithZoomSupport(this);
655+
}
656+
602657
/**
603658
* The provided ImageGcDrawer will be called on demand whenever a new variant of the
604659
* Image for an additional zoom is required. Depending on the OS-specific implementation

0 commit comments

Comments
 (0)