This is an automated email from the ASF dual-hosted git repository.
ebakke pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 12719ec2353 Switch SVG loading from the Batik library to JSVG.
12719ec2353 is described below
commit 12719ec2353f518cb4c0eb8e8b858989fd9cd598
Author: Eirik Bakke <[email protected]>
AuthorDate: Thu Nov 7 14:02:16 2024 -0500
Switch SVG loading from the Batik library to JSVG.
---
nbbuild/cluster.properties | 1 +
nbbuild/licenses/MIT-jsvg | 21 +++
nbbuild/licenses/names.properties | 1 +
platform/libs.jsvg/build.xml | 29 ++++
platform/libs.jsvg/external/binaries-list | 18 +++
platform/libs.jsvg/external/jsvg-1.6.1-license.txt | 29 ++++
platform/libs.jsvg/manifest.mf | 5 +
platform/libs.jsvg/nbproject/project.properties | 26 ++++
platform/libs.jsvg/nbproject/project.xml | 64 +++++++++
.../src/org/netbeans/libs/jsvg/Bundle.properties | 22 +++
platform/openide.util.ui.svg/nbproject/project.xml | 2 +-
.../org/openide/util/svg/DenyingElementLoader.java | 59 ++++++++
.../src/org/openide/util/svg/SVGIcon.java | 154 +++++++++++----------
.../org/openide/util/svg/SVGLoaderImplTest.java | 16 ++-
.../src/org/openide/util/svg/externalImageHref.svg | 26 ++++
.../openide/util/svg/externalImageHrefXLink.svg | 26 ++++
16 files changed, 422 insertions(+), 77 deletions(-)
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index c850dcd0db1..b9a79066f94 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 00000000000..f3a3d71f2de
--- /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 36ea7e99937..0cd108da0ea 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 00000000000..70b06619279
--- /dev/null
+++ b/platform/libs.jsvg/build.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+
+<!-- You may freely edit this file. See harness/README in the NetBeans
platform -->
+<!-- for some information on what you could do (e.g. targets to override). -->
+<!-- If you delete this file and reopen the project it will be recreated. -->
+<project name="platform/libs.jsvg" default="build" basedir=".">
+ <description>Builds the JSVG library wrapper module.</description>
+ <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/platform/libs.jsvg/external/binaries-list
b/platform/libs.jsvg/external/binaries-list
new file mode 100644
index 00000000000..9076715ac7c
--- /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 00000000000..3b8f0f66221
--- /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 00000000000..c0657cdc1e4
--- /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 00000000000..6fb34845af4
--- /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 00000000000..0053019fd85
--- /dev/null
+++ b/platform/libs.jsvg/nbproject/project.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.apisupport.project</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/nb-module-project/2">
+ <code-name-base>org.netbeans.libs.jsvg</code-name-base>
+ <module-dependencies/>
+ <public-packages>
+ <package>com.github.weisj.jsvg</package>
+ <package>com.github.weisj.jsvg.attributes</package>
+ <package>com.github.weisj.jsvg.attributes.filter</package>
+ <package>com.github.weisj.jsvg.attributes.font</package>
+ <package>com.github.weisj.jsvg.attributes.paint</package>
+ <package>com.github.weisj.jsvg.attributes.stroke</package>
+ <package>com.github.weisj.jsvg.attributes.text</package>
+ <package>com.github.weisj.jsvg.geometry</package>
+ <package>com.github.weisj.jsvg.geometry.mesh</package>
+ <package>com.github.weisj.jsvg.geometry.noise</package>
+ <package>com.github.weisj.jsvg.geometry.path</package>
+ <package>com.github.weisj.jsvg.geometry.size</package>
+ <package>com.github.weisj.jsvg.geometry.util</package>
+ <package>com.github.weisj.jsvg.nodes</package>
+ <package>com.github.weisj.jsvg.nodes.animation</package>
+ <package>com.github.weisj.jsvg.nodes.container</package>
+ <package>com.github.weisj.jsvg.nodes.filter</package>
+ <package>com.github.weisj.jsvg.nodes.mesh</package>
+ <package>com.github.weisj.jsvg.nodes.prototype</package>
+ <package>com.github.weisj.jsvg.nodes.prototype.spec</package>
+ <package>com.github.weisj.jsvg.nodes.text</package>
+ <package>com.github.weisj.jsvg.parser</package>
+ <package>com.github.weisj.jsvg.parser.css</package>
+ <package>com.github.weisj.jsvg.parser.resources</package>
+ <package>com.github.weisj.jsvg.renderer</package>
+ <package>com.github.weisj.jsvg.renderer.awt</package>
+ <package>com.github.weisj.jsvg.renderer.jdk</package>
+ <package>com.github.weisj.jsvg.util</package>
+ </public-packages>
+ <class-path-extension>
+
<runtime-relative-path>ext/jsvg-1.6.1.jar</runtime-relative-path>
+ <binary-origin>external/jsvg-1.6.1.jar</binary-origin>
+ </class-path-extension>
+ </data>
+ </configuration>
+</project>
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 00000000000..cc006f2d790
--- /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 851ebd109a7..251685f9ec8 100644
--- a/platform/openide.util.ui.svg/nbproject/project.xml
+++ b/platform/openide.util.ui.svg/nbproject/project.xml
@@ -26,7 +26,7 @@
<code-name-base>org.openide.util.ui.svg</code-name-base>
<module-dependencies>
<dependency>
-
<code-name-base>org.netbeans.libs.batik.read</code-name-base>
+ <code-name-base>org.netbeans.libs.jsvg</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
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 00000000000..6fbd29ce705
--- /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<String> attemptedExternalURLsLoaded = new
LinkedHashSet<>();
+
+ public Set<String> getAttemptedExternalURLsLoaded() {
+ return Collections.unmodifiableSet(attemptedExternalURLsLoaded);
+ }
+
+ @Override
+ public <T> T loadElement(Class<T> 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 1d5b227c5c7..48a04ec64b4 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.Dimension;
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.Map;
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<SAXSVGDocumentFactory> DOCUMENT_FACTORY =
- new ThreadLocal<SAXSVGDocumentFactory>()
+ /* 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<SVGLoader> SVG_LOADER =
+ new ThreadLocal<SVGLoader>()
{
@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<GraphicsNode> graphicsNodeWeakRef;
+ private WeakReference<SVGDocument> 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<GraphicsNode>(initialGraphicsNode);
+ this.svgDocumentStrongRef = initialSVGDocument;
+ this.svgDocumentWeakRef = new
WeakReference<SVGDocument>(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<GraphicsNode>(ret);
+ ret = loadSVGDocument(url, null);
+ svgDocumentWeakRef = new WeakReference<SVGDocument>(ret);
return ret;
}
@@ -126,40 +123,50 @@ final class SVGIcon extends CachedHiDPIIcon {
*
* @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. <image href="https://example.com/image.png">
elements. Tested in
+ testLoadImageWithExternalImageHref. */
+ List<IOException> 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. <use xlink:href="http://foobar/not/exists#text">
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 @@ final class SVGIcon extends CachedHiDPIIcon {
toSize.width = widthLimited;
toSize.height = heightLimited;
}
- return graphicsNode;
+ return svgDocument;
}
private static RenderingHints createHints() {
@@ -188,7 +195,8 @@ final class SVGIcon extends CachedHiDPIIcon {
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 @@ final class SVGIcon extends CachedHiDPIIcon {
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 c182c73593c..5aa2d7cbd22 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 class SVGLoaderImplTest extends NbTestCase {
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<LogRecord> recorded = new ArrayList<>();
@@ -64,7 +76,7 @@ public class SVGLoaderImplTest extends NbTestCase {
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 00000000000..f36ed112730
--- /dev/null
+++
b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHref.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+
+<!--
+
+ 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.
+
+-->
+
+<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0
0 100 100">
+ <image href="https://example.com/image.png" x="10" y="10" height="160"
width="380"/>
+</svg>
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 00000000000..06f17561b2f
--- /dev/null
+++
b/platform/openide.util.ui.svg/test/unit/src/org/openide/util/svg/externalImageHrefXLink.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+
+<!--
+
+ 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.
+
+-->
+
+<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0
0 100 100">
+ <image xlink:href="https://example.com/image.png" x="10" y="10"
height="160" width="380"/>
+</svg>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists