Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Proposal: Rasterization of SVGs at Runtime for Eclipse Icons #1638

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

Michael5601
Copy link

@Michael5601 Michael5601 commented Dec 6, 2024

Eclipse currently loads icons exclusively as raster graphics (e.g., .png), without support for vector formats like .svg. A major drawback of raster graphics is their inability to scale without degrading image quality. Additionally, generating icons of different sizes requires manually rasterizing SVGs outside Eclipse, leading to unnecessary effort and many icon files.

This PR introduces support for vector graphics in Eclipse, enabling SVGs to be used for icons. Existing PNG icons will continue to be loaded alongside SVGs, allowing the use of the new functionality without the need to replace all PNG files at once.


Key Features

  • Example Images:
    Screenshots showcasing the new functionality can be found below. These screenshots were taken with 125% monitor-zoom and scaling enabled with the flag -Dswt.autoScale=quarter.
PNG SVG
PNG SVG
PNG2 SVG2
PNG3 SVG3
PNG4 SVG4
  • How It Works:

    • To use SVG icons, simply place the SVG file in the bundle and reference it in the plugin.xml and other necessary locations, as is done for PNGs. No additional configuration is required.
    • At runtime, Eclipse uses the library JSVG to rasterize the SVG into a raster image of the desired size, eliminating the need for scaling. My analysis shows that JSVG is the most suitable Java library for this purpose.
    • You need to write the flag -Dswt.autoScale=quarter into your eclipse.ini file or into the run arguments of a new configuration.
  • Demonstration:
    This PR includes SVG versions of icons for the following bundles:

    • org.eclipse.search
    • org.eclipse.ui
    • org.eclipse.ui.ide
    • org.eclipse.ui.ide.application
    • org.eclipse.ui.editors
    • org.eclipse.ui.navigator

Due to this the PR of Platform UI is very large. If preferred, I can limit the changes to org.eclipse.search, allowing SVG icons to be tested specifically in the search result window.
I did not delete any exisiting PNGs.


Architecture

Eclipse icons fall into three categories, all three adressed by this PR:

  1. Standard Icons:
    These is the most common type of icons. They are loaded, scaled if needed, and displayed in the UI.

  2. Composite Icons:
    Composite icons combine a base icon with up to four overlay icons. Each component is loaded separately and then combined for display.

  3. Graphically Customized Icons:
    These icons represent disabled or "grayed-out" states. They can either be provided as pre-designed raster images or generated dynamically at runtime by applying transformations to the "enabled" version of the icon. Eclipse does not have no pre-designed SVGs. As soon as the path of the pre-designed raster graphic is removed the icon will be created at runtime.

Standard-Icons and Composite Icons are fully supported by this PR. Graphically Customized Icons are only supported if the pre-designed raster graphic is removed. The original image loaded before the customization, is generated by rasterizing a SVG. Afterwards the current automatic customization functionality creates the "grayed-out" style. This currenct functionality for customization produces bad results as seen here. This is why I want to change this behaviour in a future PR.

The solution of my future PR applies a runtime filter to SVGs before rasterization (pre-processing), which can emulate GTK or Cocoa (macOS)/Windows styles. Specifically, GTK uses a unique style for disabled icons and I can only produce results that fit to either GTK or Windows and Cocoa. I will release this feature as a follow up to this PR as soon as a solution is found for the different styles for different OS. As discussion for this topic can be found here. Alternatively I can release the PR before and we live with the other visuals for one OS. For now I recommend to use the pre-designed PNGs as usual. The future PR for the customization of icons with SVGs is nearly complete but requires further refinement before release.

The sequence diagrams below illustrate the architecture for loading Standard and Composite Icons. The new functionality introduced in this PR is highlighted in blue. The new functionality changes the ImageLoader process on the right side of the diagramms. You can see that the implementation can happen in the same place for these two icon groups:

Sequence-Diagram: Standard-Icons (Currenct Workflow)
20241206_Standard-Icons_Current

Sequence-Diagram: Standard-Icons (Improved Workflow)
20241206_Standard-Icons_Improved

Sequence-Diagram: Composite-Icons (Currenct Workflow. See also the two little referenced workflows below)
20241206_Composite-Icons_Current-1
20241206_Composite-Icons_Current-2

Sequence-Diagram: Composite-Icons (Improved Workflow)
20241206_Composite-Icons_Improved

For Graphically Customized Icons, only the current workflow will be shown in a sequence diagram here. The new workflow as described above will be part of the follow up PR. You can see that by calling URLImageDescriptor.createImage() the Standard-Icons workflow is called.

Sequence-Diagram: Disabled-Icons (Current Workflow)
20241206_Disabled-Icons_Current


Dependency Management

To enable SVG rasterization, the library JSVG is required as an external dependency. Since all rasterization logic needs to be part of Eclipse SWT, the dependency must also be included in SWT. However, SWT currently has no external dependencies, which created challenges for the integration of the Dependency:

Unsuccessful Approaches:

  1. Fragment Approach:
    Adding a fragment to SWT with the JSVG dependency failed, as SWT itself is composed of fragments, and fragments cannot depend on other fragments.

  2. Service Loader Approach:
    Adding a new bundle with the functionality and the dependency failed because SWT fragments lack a class loader to locate the new bundle. (I am not sure if this reason is correct but I tried for some hours and it did not work)

Successful Approach:

I created a new bundle containing the rasterization logic and the JSVG dependency. This bundle registers itself via a hook mechanism during initialization. To ensure the bundle is loaded, I added an initialization line to Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor).

Once JSVG is included in the target platform (with help from @HannesWell), this functionality will become fully operational.


Outstanding Issues

  1. Target Platform:
    The JSVG library must be included in the target platform.

  2. Existing PNGs:
    PNG files cannot yet be deleted, as some are referenced across bundles via hardcoded paths e.g. in platform code. Removing these files would result in errors.

  3. Early-Loaded Icons:
    A few icons (e.g., eclipse16.png) are loaded before the workbench is initialized. At this point, the rasterizer has not yet been registered. I only experienced three icons that were loaded this early but there might be more.

  4. Scaling Support for Composite Icons:
    I modified the behavior of the CompositeImageDescriptor.supportsZoomLevel(int zoom) method in Platform UI to address a limitation where it only allowed zoom levels that were exact multiples of 100 (e.g., 100, 200, 300). This restriction, caused by an unresolved bug, prevented scaling to zoom levels such as 125. Although I haven't analyzed the underlying bug yet, this change was necessary to enable proper scaling functionality.

  5. Missing or broken SVGs
    There are some icons that don't have a SVG-File or the SVG-File needs to be improved. The feature can still be used as there will be raster graphics that are loaded instead but finally this issue needs to be fixed. I will provide PRs if I find these icons.


Planned Tasks for this PR

  1. Regression Testing:
    I will add regression tests that allow automatic testing of the feature.

  2. Performance Evaluation:
    I will perform performance tests to find out if this feature is faster or slower than the current implementation. From manual testing I can say that it feels rather the same.

  3. Testing for different OS
    The ImageLoader class has specific implementations for cocoa, win32 and gtk that I needed to change. All three implementations are very similar, so I don't think there will be an issue but the cocoa and gtk implementation was no yet tested by me. I only tested on a windows system.


See also this PR for the necessary changes in Platform UI. All changes for this feature were performed in SWT and Platform UI.

Fixes #1438.

Let me know if you'd like further clarification or additional adjustments!

@BeckerWdf
Copy link
Contributor

2. PNG files cannot yet be deleted, as some are referenced across bundles via hardcoded paths e.g. in platform code. Removing these files would result in errors.

We could clean up (most of) these references across bundles so that we can delete (most of) the PNGs.

@HannesWell
Copy link
Member

Thank you @Michael5601 for this PR I'm really looking forward to this.

Withouth having it tried out yet, I have a few remarks/questions/suggestions, all based on the assumption that providing support to render vector graphics is an 'implementation' detail that does not need any or only little new APIs where technically necessary (e.g. to specify a zoom factor).

Therefore I wonder for example a new public API type ISVGRasterizer is necessary or if it should better be an internal class, just like the other new types.
I assume it's not intended to allow external contributions of custom rasterizers? And as far as I understood our discussion, on the long run SVG support could become fully built in in SWT and then we have to decide again about the way JSVG is integrated.

Splitting the steps to handle all kind of icons sounds very reasonable for me. I think this should just focus on adding support for rendering vector graphics, just as it's done.

  1. Fragment Approach:
    Adding a fragment to SWT with the JSVG dependency failed, as SWT itself is composed of fragments, and fragments cannot depend on other fragments.

It's correct that Fragments can't have own Fragments, but a (host) bundle can have an arbitrary number of fragments.
So it would be possible to make o.e.swt.svg another fragment of o.e.swt and since all fragments and the their host bundle share the same classloader code from the corresponding native SWT fragments can then access classes from the svg fragment.
Then you could use the plain Java ServiceLoader without further addo or even just load a fixed class reflectivly using Class.forName(). This would avoid the need for adding a SVGRasterizerRegistry and making that the registration happens and happens early enough.

Setting up the java ServiceLoader between OSGi bundles (not fragments) on the other hand is a bit more complicated, but also possible. Just for reference, this blog post should explain it (I don't want to go into the details here):
https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html

Copy link
Contributor

github-actions bot commented Dec 7, 2024

Test Results

  181 files   -    302    181 suites   - 302   2m 2s ⏱️ - 5m 44s
4 095 tests ±     0  4 046 ✅  -     39  49 💤 +42  0 ❌  - 3 
4 095 runs   - 12 078  4 046 ✅  - 12 034  49 💤  - 41  0 ❌  - 3 

Results for commit 10b80f3. ± Comparison against base commit 7300cb4.

This pull request skips 42 tests.
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_browser_Browser ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color[browser flags: 0]
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_custom_CCombo ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_custom_CLabel ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_custom_CTabFolder ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_custom_StyledText ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_widgets_Button ‑ test_setForegroundAlphaCheckButton
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_widgets_Button ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_widgets_Button ‑ test_setForegroundAlphaRadiokButton
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_widgets_Canvas ‑ test_setForegroundAlphaLorg_eclipse_swt_graphics_Color
org.eclipse.swt.tests.junit.Test_org_eclipse_swt_widgets_Combo ‑ test_setForegroundAlphaDropDownCombo
…

@Michael5601
Copy link
Author

Thank you for the comment, I will check all your remarks soon.

Setting up the java ServiceLoader between OSGi bundles (not fragments) on the other hand is a bit more complicated, but also possible. Just for reference, this blog post should explain it (I don't want to go into the details here): https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html

To this point I can already say that I tried it with the same article but I wasn't successful.

@HeikoKlare
Copy link
Contributor

Therefore I wonder for example a new public API type ISVGRasterizer is necessary or if it should better be an internal class, just like the other new types. I assume it's not intended to allow external contributions of custom rasterizers? And as far as I understood our discussion, on the long run SVG support could become fully built in in SWT and then we have to decide again about the way JSVG is integrated.

That's something we should discuss and agree on. I would not in favor of tightly integrating a specific SVG rasterizer into SWT. Having it interchangeable ensures low coupling and gives the flexibility to exchange it without rebuilding SWT (by just providing some other fragment/bundle/... that contains an alternative rasterizer implementation). We could still think of making that interface internal for now, so that the interface is not public but in case you would want to provide a different rasterizer it would still be possible (with potentially a warning).

  1. Fragment Approach:
    Adding a fragment to SWT with the JSVG dependency failed, as SWT itself is composed of fragments, and fragments cannot depend on other fragments.

It's correct that Fragments can't have own Fragments, but a (host) bundle can have an arbitrary number of fragments. So it would be possible to make o.e.swt.svg another fragment of o.e.swt and since all fragments and the their host bundle share the same classloader code from the corresponding native SWT fragments can then access classes from the svg fragment. Then you could use the plain Java ServiceLoader without further addo or even just load a fixed class reflectivly using Class.forName(). This would avoid the need for adding a SVGRasterizerRegistry and making that the registration happens and happens early enough.

For some more clarifiation on using a fragment: If we are not mistaken, to provide a fragment with a concrete rasterizer implementation, the rasterizer interface needs to be placed directly in the SWT host bundle, not in some common package that is mapped into all the native fragments like done for all the other SWT code. Otherwise, the SVG fragment would be tied to the presence of another fragment providing that interface, which (reasonably) seems to be prohibited. As a consequence, that interface would become the first source element to be placed directly in the SWT host bundle, while all the other code is placed in the native fragments. In addition, we need to reference that interface from within the native fragments (to make use a rasterizer in SWT code). With the current configuration of the bundles/fragment, this is not possible. The SWT host bundle has to be added to the classpath of the native fragments to access the interface via adding the PDE required plugins container to its classpath (i.e., to add the classpath entry <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>). All this may not be prohitibitive, but it's all changes to the current configuration of the SWT host and fragments that need to be considered.

Setting up the java ServiceLoader between OSGi bundles (not fragments) on the other hand is a bit more complicated, but also possible. Just for reference, this blog post should explain it (I don't want to go into the details here): https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html

I just want to add that I also tried to create a minimal reproducer for using a ServiceLoader across OSGi bundles, but I also failed, just like Michael. The necessary capabilities added to the manifests do not even show up when listing the capabilities of the bundles via the OSGi console. Probably, I am / we are doing something wrong here.

@Michael5601
Copy link
Author

I edited the PR message and added the following points:

  1. Planned Tasks for this PR: I will include regression tests and I will perform a performance evaluation. The feature also needs to be tested for gtk and cocoa as they have different ImageLoader implementations.
  2. New Outstanding issue: There are missing or broken SVGs that do not need to be fixed for this feature to work but if we plan to remove all PNGs finally this issue needs to be resolved.

Feature Proposal: Rasterization of SVGs at Runtime for Eclipse Icons
Fixes eclipse-platform#1438

Eclipse currently loads icons exclusively as raster graphics (e.g., `.png`), without support for vector formats like `.svg`. A major drawback of raster graphics is their inability to scale without degrading image quality. Additionally, generating icons of different sizes requires manually rasterizing SVGs outside Eclipse, leading to unnecessary effort and many icon files.

This PR introduces support for vector graphics in Eclipse, enabling SVGs to be used for icons. Existing PNG icons will continue to be loaded alongside SVGs, allowing the use of the new functionality without the need to replace all PNG files at once.

---
- **How It Works**:
  - To use SVG icons, simply place the SVG file in the bundle and reference it in the `plugin.xml` and other necessary locations, as is done for PNGs. No additional configuration is required.
  - At runtime, Eclipse uses the library JSVG to rasterize the SVG into a raster image of the desired size, eliminating the need for scaling. My analysis shows that JSVG is the most suitable Java library for this purpose.
  - You need to write the flag `-Dswt.autoScale=quarter` into your `eclipse.ini` file or into the run arguments of a new configuration.
Copy link
Contributor

@laeubi laeubi left a comment

Choose a reason for hiding this comment

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

I think we should follow the java recommendation for interface names here the I prefix is more an eclipse thing and even there we do not follow this anymore and I don't have seen it in SWT aynwhere

Copy link
Contributor

@laeubi laeubi left a comment

Choose a reason for hiding this comment

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

I think the stream handling is flawed at the moment and reading SVG documents should be done using streams or URLs.

The caller needs to make sure the method is called with an SVG file.
The check now only checks the first byte.
@Michael5601
Copy link
Author

Michael5601 commented Dec 11, 2024

Please see this Draft for the Follow-up-functionality for the automatic customization of graphically customized icons as announced previously in this PR.

The functionality is complete but the draft is meant as a base for discussion. All changes to this PR will be done also in the draft.

@HannesWell
Copy link
Member

HannesWell commented Dec 11, 2024

Therefore I wonder for example a new public API type ISVGRasterizer is necessary or if it should better be an internal class, just like the other new types. I assume it's not intended to allow external contributions of custom rasterizers? And as far as I understood our discussion, on the long run SVG support could become fully built in in SWT and then we have to decide again about the way JSVG is integrated.

That's something we should discuss and agree on.

Yes, absolutely. I suggest we discuss this in a separate issue, in parallel to this PR.

Setting up the java ServiceLoader between OSGi bundles (not fragments) on the other hand is a bit more complicated, but also possible. Just for reference, this blog post should explain it (I don't want to go into the details here): https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html

I just want to add that I also tried to create a minimal reproducer for using a ServiceLoader across OSGi bundles, but I also failed, just like Michael. The necessary capabilities added to the manifests do not even show up when listing the capabilities of the bundles via the OSGi console. Probably, I am / we are doing something wrong here.

Besides adding the correct required and provided capabilities to the provider and consumer of the service (implementation), you also have to make sure that aries.spifly as well as the provider of the service (implementation) are auto-started at an appropriated level, see for example how it's done for slf4j-simple providing a logging-provider consumed by the slf4j-api bundle:
https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/blob/02e51912906b367d441fb0d120c7fd3bc3990dad/eclipse.platform.releng.tychoeclipsebuilder/eclipse.platform.repository/sdk.product#L193-L200

Everyone building products or launching Eclipse-apps from a workspace that include this SVG support for SWT would have to configure this. This would IMHO be cumbersome and to avoid all these difficulties I strongly would like to avoid the need for the OSGI Service Loader mediator in this case.

  1. Fragment Approach:
    Adding a fragment to SWT with the JSVG dependency failed, as SWT itself is composed of fragments, and fragments cannot depend on other fragments.

It's correct that Fragments can't have own Fragments, but a (host) bundle can have an arbitrary number of fragments. So it would be possible to make o.e.swt.svg another fragment of o.e.swt and since all fragments and the their host bundle share the same classloader code from the corresponding native SWT fragments can then access classes from the svg fragment. Then you could use the plain Java ServiceLoader without further addo or even just load a fixed class reflectivly using Class.forName(). This would avoid the need for adding a SVGRasterizerRegistry and making that the registration happens and happens early enough.

For some more clarifiation on using a fragment: If we are not mistaken, to provide a fragment with a concrete rasterizer implementation, the rasterizer interface needs to be placed directly in the SWT host bundle, not in some common package that is mapped into all the native fragments like done for all the other SWT code.

That's right. The only disadvantage I can think of for having code in the o.e.swt host bundle to, would be that for plain-Java/non-OSGi apps o.e.swt would then also need o.e.swt on the classpath, while they only need the native fragment of the current platform now. So I guess that wouldn't be ideal, altough I don't know if it's forbidden by a rule.
But maybe we could make that change only for the compilation in the workspace, because at runtime because all fragments and their host share the same classloader, the actual location of a class-file among them, is irrelevant (maybe with multiple occurrences of the same class).
But it would also lead to another problem: Because SVGRasterizer returns an ImageData object that class must be moved to o.e.swt too and with it it's whole dependency-closure and eventually we would more or less revert:

But I tried a few things out and had another idea:
If o.e.swt.svg is a fragment of o.e.swt, we could simply add an explicit requirement to the native fragments to the build-path of o.e.swt.svg. See the details below in the code-remarks.
But that should be a solution that seems feasible.

Another option would be to not provide an interface SVGRasterizer at all and just load the class JSVGRasterizer reflectively using Class.forName() and also calling all relevant methods reflectively (or a method handle to improve performance).
This way a special interface to implement would not be necessary at all, but it would also be a bit more 'bare-metal'.

Edit: Thinking about this again, this wouldn't save much since e.g. the ImageData type is still required, which leads to the same problem again.

Yet another option would be to avoid a new o.e.swt.svg bundle/fragment and add all code to interact with JSVG, which is not that much, directly into o.e.swt respectivly it's native fragments and make the dependency to JSVG optional and be prepared for it's absence! This way one would only have to add jsvg to an application/product for OSGi-runtimes and plain Java apps and not also o.e.swt.svg. Hopefully it has OSGi metadata soon:

Of course this would more or less make it impossible to supply alternative rasterizer. But I cannot tell if it's realistic that custom ones will be supplied or not and we are just over-engineering here?
Of course it shouldn't be integrated to tightly, so that an exchange in the future is feasible if necessary. But that's maybe part of the discussion of the very first point of this comment.

Comment on lines +8 to +9
Export-Package: org.eclipse.swt.svg
Import-Package: org.eclipse.swt.graphics
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Export-Package: org.eclipse.swt.svg
Import-Package: org.eclipse.swt.graphics
Fragment-Host: org.eclipse.swt
Export-Package: org.eclipse.swt.svg

<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.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="libs/jsvg-1.6.1.jar"/>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<classpathentry kind="lib" path="libs/jsvg-1.6.1.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.swt.win32.win32.x86_64" />
<classpathentry kind="lib" path="libs/jsvg-1.6.1.jar"/>

This makes this project on o.e.swt.win32.win32.x86_64 and adds the latter to the classpath of the former, similar like how it's happening at runtime.

Of course this now only works for win32.x86_64. I also added other swt-fragments, but it looks like this is not optional and on a first sight I didn't found a way to make it optional. But it is possible to turn incomplete-classpath errors into warnings by adding org.eclipse.jdt.core.incompleteClasspath=warning to .settings/org.eclipse.jdt.core.prefs.
And to make it work in the build it is hopefully sufficient to add a pom.xml to the project where, depending on the running platform, an explicit dependency to the corresponding native fragment is added.

Copy link
Author

Choose a reason for hiding this comment

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

I have to admit that I am not very experienced with this topic. It seems you have an idea how this could work with fragments if I read it right. This would be very nice. It would be great if we could have a call where you can explain this approach to me.

@laeubi
Copy link
Contributor

laeubi commented Dec 12, 2024

For some more clarifiation on using a fragment: If we are not mistaken, to provide a fragment with a concrete rasterizer implementation, the rasterizer interface needs to be placed directly in the SWT host bundle, not in some common package that is mapped into all the native fragments like done for all the other SWT code.

This is not true, all fragments are merged with the host and therefore you have one big class space, it might be that the IDE (or Tycho) currently have some limitations in this regard but we could/should fix that instead of making things harder than required.

A ServiceLoader approach seem suitable also here for me, no need to complicate the thing with OSGi SPI, this is only for applications that are not aware of OSGi at all and this is not the case here and also not needed.

@Michael5601
Copy link
Author

Yes, absolutely. I suggest we discuss this in a separate issue, in parallel to this PR.

I agree. I created this discussion for this topic.

@Michael5601
Copy link
Author

I just realised that cocoa and gtk not only have different implementation for ImageLoader but also for the Image class. I can of course also implement my changes there but right now I can't test the changes.

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.

Improving Eclipse Icon Scaling by Supporting Vectorized Icons
8 participants