diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties index c850dcd0db19..b9a79066f948 100644 --- a/nbbuild/cluster.properties +++ b/nbbuild/cluster.properties @@ -189,6 +189,7 @@ nb.cluster.platform=\ libs.jna,\ libs.jna.platform,\ libs.jsr223,\ + libs.jsvg,\ libs.junit4,\ libs.junit5,\ libs.osgi,\ diff --git a/nbbuild/licenses/MIT-jsvg b/nbbuild/licenses/MIT-jsvg new file mode 100644 index 000000000000..f3a3d71f2de5 --- /dev/null +++ b/nbbuild/licenses/MIT-jsvg @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-2024 Jannis Weis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/nbbuild/licenses/names.properties b/nbbuild/licenses/names.properties index 36ea7e99937c..0cd108da0ea5 100644 --- a/nbbuild/licenses/names.properties +++ b/nbbuild/licenses/names.properties @@ -69,6 +69,7 @@ MIT-phpstan=MIT license PHPStan variant MIT-validator=MIT license validator variant MIT-vscode=MIT license for VSCode MIT-vscode-ext=MIT license VS Code variant +MIT-jsvg=MIT license JSVG variant MPL-1.0=MPL 1.0 license CDDL-SPL=CDDL 1.0 + SPL 1.0 W3C2=W3C Software and Document Notice and License diff --git a/platform/libs.jsvg/build.xml b/platform/libs.jsvg/build.xml new file mode 100644 index 000000000000..70b06619279c --- /dev/null +++ b/platform/libs.jsvg/build.xml @@ -0,0 +1,29 @@ + + + + + + + + Builds the JSVG library wrapper module. + + diff --git a/platform/libs.jsvg/external/binaries-list b/platform/libs.jsvg/external/binaries-list new file mode 100644 index 000000000000..9076715ac7c0 --- /dev/null +++ b/platform/libs.jsvg/external/binaries-list @@ -0,0 +1,18 @@ +# 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. + +A84D34480044DB51A1448E9C0E32BD284B797288 com.github.weisj:jsvg:1.6.1 diff --git a/platform/libs.jsvg/external/jsvg-1.6.1-license.txt b/platform/libs.jsvg/external/jsvg-1.6.1-license.txt new file mode 100644 index 000000000000..3b8f0f662212 --- /dev/null +++ b/platform/libs.jsvg/external/jsvg-1.6.1-license.txt @@ -0,0 +1,29 @@ +Name: JSVG +Version: 1.6.1 +Description: JSVG - A Java SVG implementation +License: MIT-jsvg +Origin: JSVG +URL: https://github.com/weisJ/jsvg +Files: jsvg-1.6.1.jar + +MIT License + +Copyright (c) 2021-2024 Jannis Weis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/platform/libs.jsvg/manifest.mf b/platform/libs.jsvg/manifest.mf new file mode 100644 index 000000000000..c0657cdc1e4c --- /dev/null +++ b/platform/libs.jsvg/manifest.mf @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +OpenIDE-Module: org.netbeans.libs.jsvg +OpenIDE-Module-Implementation-Version: 1 +OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/jsvg/Bundle.properties +AutoUpdate-Show-In-Client: false diff --git a/platform/libs.jsvg/nbproject/project.properties b/platform/libs.jsvg/nbproject/project.properties new file mode 100644 index 000000000000..6fb34845af4e --- /dev/null +++ b/platform/libs.jsvg/nbproject/project.properties @@ -0,0 +1,26 @@ +# 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. + +file.reference.jsvg-1.6.1.jar=external/jsvg-1.6.1.jar +release.external/jsvg-1.6.1.jar=modules/ext/jsvg-1.6.1.jar + +is.autoload=true +javac.source=1.8 + +nbm.homepage=https://github.com/weisJ/jsvg +sigtest.gen.fail.on.error=false +spec.version.base=1.22.0 diff --git a/platform/libs.jsvg/nbproject/project.xml b/platform/libs.jsvg/nbproject/project.xml new file mode 100644 index 000000000000..0053019fd856 --- /dev/null +++ b/platform/libs.jsvg/nbproject/project.xml @@ -0,0 +1,64 @@ + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.libs.jsvg + + + com.github.weisj.jsvg + com.github.weisj.jsvg.attributes + com.github.weisj.jsvg.attributes.filter + com.github.weisj.jsvg.attributes.font + com.github.weisj.jsvg.attributes.paint + com.github.weisj.jsvg.attributes.stroke + com.github.weisj.jsvg.attributes.text + com.github.weisj.jsvg.geometry + com.github.weisj.jsvg.geometry.mesh + com.github.weisj.jsvg.geometry.noise + com.github.weisj.jsvg.geometry.path + com.github.weisj.jsvg.geometry.size + com.github.weisj.jsvg.geometry.util + com.github.weisj.jsvg.nodes + com.github.weisj.jsvg.nodes.animation + com.github.weisj.jsvg.nodes.container + com.github.weisj.jsvg.nodes.filter + com.github.weisj.jsvg.nodes.mesh + com.github.weisj.jsvg.nodes.prototype + com.github.weisj.jsvg.nodes.prototype.spec + com.github.weisj.jsvg.nodes.text + com.github.weisj.jsvg.parser + com.github.weisj.jsvg.parser.css + com.github.weisj.jsvg.parser.resources + com.github.weisj.jsvg.renderer + com.github.weisj.jsvg.renderer.awt + com.github.weisj.jsvg.renderer.jdk + com.github.weisj.jsvg.util + + + ext/jsvg-1.6.1.jar + external/jsvg-1.6.1.jar + + + + diff --git a/platform/libs.jsvg/src/org/netbeans/libs/jsvg/Bundle.properties b/platform/libs.jsvg/src/org/netbeans/libs/jsvg/Bundle.properties new file mode 100644 index 000000000000..cc006f2d790e --- /dev/null +++ b/platform/libs.jsvg/src/org/netbeans/libs/jsvg/Bundle.properties @@ -0,0 +1,22 @@ +# 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. + + +OpenIDE-Module-Name=JSVG Library +OpenIDE-Module-Short-Description=JSVG Library +OpenIDE-Module-Long-Description=Contains the JSVG library, for reading and painting SVG files. +OpenIDE-Module-Display-Category=Libraries diff --git a/platform/openide.util.ui.svg/nbproject/project.xml b/platform/openide.util.ui.svg/nbproject/project.xml index 851ebd109a70..251685f9ec8d 100644 --- a/platform/openide.util.ui.svg/nbproject/project.xml +++ b/platform/openide.util.ui.svg/nbproject/project.xml @@ -26,7 +26,7 @@ org.openide.util.ui.svg - org.netbeans.libs.batik.read + org.netbeans.libs.jsvg diff --git a/platform/openide.util.ui.svg/src/org/openide/util/svg/DenyingElementLoader.java b/platform/openide.util.ui.svg/src/org/openide/util/svg/DenyingElementLoader.java new file mode 100644 index 000000000000..6fbd29ce7052 --- /dev/null +++ b/platform/openide.util.ui.svg/src/org/openide/util/svg/DenyingElementLoader.java @@ -0,0 +1,59 @@ +/* + * 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.openide.util.svg; + +import com.github.weisj.jsvg.attributes.AttributeParser; +import com.github.weisj.jsvg.parser.ElementLoader; +import com.github.weisj.jsvg.parser.ParsedDocument; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +class DenyingElementLoader implements ElementLoader { + private final Set attemptedExternalURLsLoaded = new LinkedHashSet<>(); + + public Set getAttemptedExternalURLsLoaded() { + return Collections.unmodifiableSet(attemptedExternalURLsLoaded); + } + + @Override + public T loadElement(Class type, String value, + ParsedDocument document, AttributeParser attributeParser) + { + /* Same logic as in com.github.weisj.jsvg.parser.DefaultElementLoader for the + AllowExternalResources.DENY case, but gathering up the attempted externally loaded URLs so + we can make the whole loading operation fail and make testLoadImageWithExternalUseXlinkHref + pass. */ + String url = attributeParser.parseUrl(value); + if (url == null) { + return null; + } + if (url.contains("#")) { + String[] parts = url.split("#", 2); + String name = parts[0]; + if (!name.isEmpty()) { + attemptedExternalURLsLoaded.add(value); + return null; + } + return document.getElementById(type, parts[1]); + } else { + return document.getElementById(type, url); + } + } +} diff --git a/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGIcon.java b/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGIcon.java index 1d5b227c5c75..48a04ec64b49 100644 --- a/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGIcon.java +++ b/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGIcon.java @@ -23,7 +23,6 @@ import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; -import java.awt.geom.Dimension2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.io.IOException; @@ -35,21 +34,17 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Icon; -import org.apache.batik.anim.dom.SAXSVGDocumentFactory; -import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.bridge.DocumentLoader; -import org.apache.batik.bridge.ExternalResourceSecurity; -import org.apache.batik.bridge.GVTBuilder; -import org.apache.batik.bridge.NoLoadExternalResourceSecurity; -import org.apache.batik.bridge.UserAgent; -import org.apache.batik.bridge.UserAgentAdapter; -import org.apache.batik.ext.awt.image.GraphicsUtil; -import org.apache.batik.gvt.GraphicsNode; -import org.apache.batik.util.ParsedURL; -import org.apache.batik.util.XMLResourceDescriptor; +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.ResourceLoader; +import com.github.weisj.jsvg.parser.SVGLoader; +import com.github.weisj.jsvg.renderer.awt.NullPlatformSupport; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; import org.openide.util.CachedHiDPIIcon; import org.openide.util.Parameters; -import org.w3c.dom.Document; /** * An icon loaded from an SVG file resource. Renders in high resolution on HiDPI displays. @@ -62,62 +57,64 @@ final class SVGIcon extends CachedHiDPIIcon { enough to avoid an OutOfMemoryError but large enough to cater for most SVG loading scenarios. Photoshop had 10000 pixels as a maximum limit for many years. */ private static final int MAX_DIMENSION_PIXELS = 8192; - // XML document factories are expensive to initialize, so do it once per thread only. - private static final ThreadLocal DOCUMENT_FACTORY = - new ThreadLocal() + /* XML document factories are expensive to initialize, so do it once per thread only. This + optimization was originally done for the Batik SVG library, but I suspect it might be beneficial + for JSVG as well. The SVGLoader constructor does initialize some XML parser stuff. */ + private static final ThreadLocal SVG_LOADER = + new ThreadLocal() { @Override - protected SAXSVGDocumentFactory initialValue() { - return new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName()); + protected SVGLoader initialValue() { + return new SVGLoader(); } }; private final URL url; /** - * Cache of the parsed SVG document. Just painting the GraphicsNode is much faster than also + * Cache of the parsed SVG document. Just painting the SVGDocument is probably faster than also * re-parsing the underlying SVG file, yet we want to avoid keeping potentially complex object - * trees in memory for the lifetime of the Icon instance. Thus we allow the GraphicsNode to be + * trees in memory for the lifetime of the Icon instance. Thus we allow the SVGDocument to be * garbage collected after the first paint. The rasterized bitmap will be cached separately by * the superclass. */ - private WeakReference graphicsNodeWeakRef; + private WeakReference svgDocumentWeakRef; /** - * A strong reference version of {@link #graphicsNodeWeakRef}, which can be set to ensure that - * the latter is not yet garbage collected. Used to ensure that the initially loaded - * GraphicsNode is cached at least until the first time the icon is painted. May be null. + * A strong reference version of {@link #svgDocumentWeakRef}, which can be set to ensure that + * the latter is not yet garbage collected. Used to ensure that the initially loaded SVGDocument + * is cached at least until the first time the icon is painted. May be null. */ - private GraphicsNode graphicsNodeStrongRef; + private SVGDocument svgDocumentStrongRef; - private SVGIcon(URL url, GraphicsNode initialGraphicsNode, int width, int height) { + private SVGIcon(URL url, SVGDocument initialSVGDocument, int width, int height) { super(width, height); Parameters.notNull("url", url); - Parameters.notNull("initialGraphicsNode", initialGraphicsNode); + Parameters.notNull("initialSVGDocument", initialSVGDocument); this.url = url; - this.graphicsNodeStrongRef = initialGraphicsNode; - this.graphicsNodeWeakRef = new WeakReference(initialGraphicsNode); + this.svgDocumentStrongRef = initialSVGDocument; + this.svgDocumentWeakRef = new WeakReference(initialSVGDocument); } public static Icon load(URL url) throws IOException { Parameters.notNull("url", url); Dimension size = new Dimension(); - GraphicsNode initialGraphicsNode = loadGraphicsNode(url, size); - return new SVGIcon(url, initialGraphicsNode, size.width, size.height); + SVGDocument initialSVGDocument = loadSVGDocument(url, size); + return new SVGIcon(url, initialSVGDocument, size.width, size.height); } /** - * Get the {@code GraphicsNode}, re-loading it from the original resource if a cached instance + * Get the {@code SVGDocument}, re-loading it from the original resource if a cached instance * is no longer available. Once this method has been called at least once, garbage collection * may cause the cache to be cleared. */ - private synchronized GraphicsNode getGraphicsNode() throws IOException { - GraphicsNode ret = graphicsNodeWeakRef.get(); + private synchronized SVGDocument getSVGDocument() throws IOException { + SVGDocument ret = svgDocumentWeakRef.get(); if (ret != null) { - // Allow the GraphicsNode to be garbage collected after the initial paint. - graphicsNodeStrongRef = null; + // Allow the SVGDocument to be garbage collected after the initial paint. + svgDocumentStrongRef = null; return ret; } - ret = loadGraphicsNode(url, null); - graphicsNodeWeakRef = new WeakReference(ret); + ret = loadSVGDocument(url, null); + svgDocumentWeakRef = new WeakReference(ret); return ret; } @@ -126,40 +123,50 @@ private synchronized GraphicsNode getGraphicsNode() throws IOException { * * @param toSize if not null, will be set to the image's size */ - private static GraphicsNode loadGraphicsNode(URL url, Dimension toSize) - throws IOException - { + private static SVGDocument loadSVGDocument(URL url, Dimension toSize) throws IOException { Parameters.notNull("url", url); - final GraphicsNode graphicsNode; - final Dimension2D documentSize; - final Document doc; + + final SVGDocument svgDocument; + FloatSize documentSize; InputStream is = url.openStream(); try { - // See http://batik.2283329.n4.nabble.com/rendering-directly-to-java-awt-Graphics2D-td3716202.html - SAXSVGDocumentFactory factory = DOCUMENT_FACTORY.get(); - /* Don't provide an URI here; we shouldn't commit to supporting relative links from - loaded SVG documents. */ - doc = factory.createDocument(null, is); - // Disallow external resource dereferences - UserAgent userAgent = new UserAgentAdapter() { - @Override - public ExternalResourceSecurity getExternalResourceSecurity( - ParsedURL resourceURL, ParsedURL docURL) { - return new NoLoadExternalResourceSecurity(); - } + // Explicitly deny loading of external URLs. + + /* Handle e.g. elements. Tested in + testLoadImageWithExternalImageHref. */ + List externalResourceExceptions = new ArrayList<>(); + ResourceLoader resourceLoader = (URI nnuri) -> { + IOException e = new IOException("External resource loading from SVG file not permitted ("+ + nnuri + " from " + url + ")"); + externalResourceExceptions.add(e); + throw e; }; - DocumentLoader loader = new DocumentLoader(userAgent); - BridgeContext bctx = new BridgeContext(userAgent, loader); - try { - bctx.setDynamicState(BridgeContext.STATIC); - graphicsNode = new GVTBuilder().build(bctx, doc); - documentSize = bctx.getDocumentSize(); - } finally { - bctx.dispose(); + /* Handle e.g. elements. Tested in + testLoadImageWithExternalUseXlinkHref. */ + DenyingElementLoader elementLoader = new DenyingElementLoader(); + + svgDocument = SVG_LOADER.get().load(is, null, LoaderContext.builder() + .resourceLoader(resourceLoader) + .elementLoader(elementLoader) + .build()); + if (!elementLoader.getAttemptedExternalURLsLoaded().isEmpty()) { + throw new IOException("SVG loading failed; external document loading prohibited (" + + elementLoader.getAttemptedExternalURLsLoaded() + ")"); + } + if (!externalResourceExceptions.isEmpty()) { + IOException e = new IOException("SVG loading failed due to disallowed external resources"); + for (IOException e2 : externalResourceExceptions) { + e.addSuppressed(e2); + } + throw e; + } + if (svgDocument == null) { + throw new IOException( + "SVG loading failed for " + url + " (SVGLoader.load returned null)"); } + documentSize = svgDocument.size(); } catch (RuntimeException e) { - /* Rethrow the many different exceptions that can occur when parsing invalid SVG files; - DOMException, BridgeException etc. */ + /* Rethrow any uncaught exceptions that could be thrown when parsing invalid SVG files. */ throw new IOException("Error parsing SVG file", e); } finally { is.close(); @@ -180,7 +187,7 @@ public ExternalResourceSecurity getExternalResourceSecurity( toSize.width = widthLimited; toSize.height = heightLimited; } - return graphicsNode; + return svgDocument; } private static RenderingHints createHints() { @@ -188,7 +195,8 @@ private static RenderingHints createHints() { hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); /* Ensure that outlined strokes (strokes converted to solid shapes) appear the same as - regular strokes, as they do during editing in Adobe Illustrator. */ + regular strokes, as they do during editing in Adobe Illustrator. This hint is also + specifically recommended by JSVG's README ( https://github.com/weisJ/jsvg ). */ hints.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); return new RenderingHints(hints); } @@ -198,15 +206,13 @@ protected Image createAndPaintImage( Component c, ColorModel colorModel, int deviceWidth, int deviceHeight, double scale) { BufferedImage img = createBufferedImage(colorModel, deviceWidth, deviceHeight); - /* Use Batik's createGraphics method to improve performance and avoid the - "Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint" warning. */ - final Graphics2D g = GraphicsUtil.createGraphics(img); + final Graphics2D g = img.createGraphics(); try { g.scale(scale, scale); try { - GraphicsNode graphicsNode = getGraphicsNode(); + SVGDocument svgDocument = getSVGDocument(); g.addRenderingHints(createHints()); - graphicsNode.paint(g); + svgDocument.renderWithPlatform(NullPlatformSupport.INSTANCE, g, null); } catch (IOException e) { LOG.log(Level.WARNING, "Unexpected exception while re-loading an SVG file that previously loaded successfully", e); diff --git a/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/SVGLoaderImplTest.java b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/SVGLoaderImplTest.java index c182c73593c9..5aa2d7cbd22c 100644 --- a/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/SVGLoaderImplTest.java +++ b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/SVGLoaderImplTest.java @@ -44,7 +44,19 @@ public void testLoadInnocentImage() throws Exception { assertNotNull("Image must not load", im); } - public void testLoadImageWithExternalHref() throws Exception { + public void testLoadImageWithExternalUseHrefXlink() throws Exception { + testLoadImageWithExternalHref("org/openide/util/svg/externalHref.svg"); + } + + public void testLoadImageWithExternalImageHrefXLink() throws Exception { + testLoadImageWithExternalHref("org/openide/util/svg/externalImageHrefXLink.svg"); + } + + public void testLoadImageWithExternalImageHref() throws Exception { + testLoadImageWithExternalHref("org/openide/util/svg/externalImageHref.svg"); + } + + public void testLoadImageWithExternalHref(String image) throws Exception { class H extends Handler { List recorded = new ArrayList<>(); @@ -64,7 +76,7 @@ public void close() throws SecurityException { H h = new H(); Logger.getLogger(ImageUtilities.class.getName()).addHandler(h); try { - Image im = ImageUtilities.loadImage("org/openide/util/svg/externalHref.svg", false); // NOI18N + Image im = ImageUtilities.loadImage(image, false); // NOI18N assertNull("Image must not load", im); } finally { Logger.getLogger(ImageUtilities.class.getName()).removeHandler(h); diff --git a/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHref.svg b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHref.svg new file mode 100644 index 000000000000..f36ed1127309 --- /dev/null +++ b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHref.svg @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHrefXLink.svg b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHrefXLink.svg new file mode 100644 index 000000000000..06f17561b2f4 --- /dev/null +++ b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHrefXLink.svg @@ -0,0 +1,26 @@ + + + + + + + +