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

commit 51a01eb9cbfc6f342a1827d47f0b37e1b2f070a3
Author: Eirik Bakke <[email protected]>
AuthorDate: Sat Jun 1 00:20:11 2019 -0400

    [NETBEANS-2604] Support SVG icon loading from ImageUtilities
    
    As a part of the effort to make NetBeans look better on HiDPI displays, the
    ImageUtilities class has now been completely updated to support scalable
    implementations of the java.awt.Icon interface, and to support loading of 
icons
    and images from SVG files. If an SVG file resource exists with the same base
    name as an existing bitmap icon, and the SVG loader implementation modules 
is
    installed, the SVG file will be loaded instead (e.g. "icon.svg" will be 
loaded
    instead of "icon.png"). SVG file resources can also be loaded explicitly.
    
    Details:
    * Have ImageUtilities support SVG image loading via an optional pluggable
      service provider, and add an implementation based on the Batik SVG 
library.
      The latter is enabled by default in the "platform" cluster.
    * Add SVG versions of the Undo/Redo action icons (visible in the Edit menu 
and
      in the NetBeans toolbar in "Small Toolbar Icons" mode). This will serve to
      test SVG icon loading and painting.
    * Moved the o.apache.commons.io and o.apache.commons.logging modules from 
the
      "ide" cluster and into the "platform" cluster, as Batik depends on these
      libraries.
    * Refactor, clean up, and generalize ImageUtilities.getLoader; it is used to
      fetch and cache both the ClassLoader and the SVGLoader implementation. The
      SVG loader implementation module will only be loaded once an actual SVG 
file
      is found and needs to be loaded.
---
 nbbuild/cluster.properties                         |   6 +-
 .../licenses/Apache-2.0-XML-Commons-APIs           |  61 +++++-
 .../libs.batik.read}/build.xml                     |   8 +-
 .../external/batik-1.12-license.txt                |  10 +-
 .../libs.batik.read/external/batik-1.12-notice.txt |  18 ++
 platform/libs.batik.read/external/binaries-list    |  34 +++
 .../external/xml-apis-ext-1.3.04-license.txt       |  65 +++++-
 .../external/xml-apis-ext-1.3.04-notice.txt        |  10 +
 .../external/xmlgraphics-commons-2.4-license.txt   |   9 +-
 .../external/xmlgraphics-commons-2.4-notice.txt    |   5 +
 platform/libs.batik.read/manifest.mf               |   5 +
 .../libs.batik.read/nbproject/project.properties   |  56 +++++
 platform/libs.batik.read/nbproject/project.xml     | 203 ++++++++++++++++++
 .../org/netbeans/libs/batik/read/Bundle.properties |   8 +-
 {ide => platform}/o.apache.commons.io/build.xml    |   2 +-
 .../o.apache.commons.io/external/binaries-list     |   0
 .../external/commons-io-1.4-license.txt            |   0
 .../external/commons-io-1.4-notice.txt             |   0
 {ide => platform}/o.apache.commons.io/manifest.mf  |   0
 .../nbproject/project.properties                   |   0
 .../o.apache.commons.io/nbproject/project.xml      |   0
 .../o.apache.commons.logging/build.xml             |   2 +-
 .../external/binaries-list                         |   0
 .../external/commons-logging-1.1.1-license.txt     |   0
 .../external/commons-logging-1.1.1-notice.txt      |   0
 .../o.apache.commons.logging/manifest.mf           |   0
 .../nbproject/project.properties                   |   0
 .../o.apache.commons.logging/nbproject/project.xml |   0
 .../src/org/openide/resources/actions/redo.svg     |  82 +++++++
 .../src/org/openide/resources/actions/undo.svg     |  82 +++++++
 .../openide.util.ui.svg}/build.xml                 |   4 +-
 platform/openide.util.ui.svg/manifest.mf           |   4 +
 .../nbproject/project.properties                   |   5 +-
 .../nbproject/project.xml                          |  51 ++---
 .../src/org/openide/util/svg/Bundle.properties     |   7 +-
 .../src/org/openide/util/svg/SVGIcon.java          | 209 ++++++++++++++++++
 .../src/org/openide/util/svg/SVGLoaderImpl.java    |  33 +++
 platform/openide.util.ui/apichanges.xml            |  27 +++
 platform/openide.util.ui/arch.xml                  |   7 +-
 platform/openide.util.ui/nbproject/project.xml     |   1 +
 .../src/org/openide/util/CachedHiDPIIcon.java      |  81 +++++--
 .../src/org/openide/util/FilteredIcon.java         |  11 +-
 .../src/org/openide/util/ImageUtilities.java       | 236 ++++++++++++++-------
 .../src/org/openide/util/spi/SVGLoader.java        |  40 ++++
 .../openide/util/ImageUtilitiesGetLoaderTest.java  |   4 +-
 .../modules/javascript/nodejs/ui/resources/npm.svg |   2 +-
 46 files changed, 1215 insertions(+), 173 deletions(-)

diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index 588849e..783e5ba 100644
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -224,6 +224,7 @@ nb.cluster.platform=\
         keyring.fallback,\
         keyring.impl,\
         lib.uihandler,\
+        libs.batik.read,\
         libs.felix,\
         libs.javafx,\
         libs.jna,\
@@ -247,6 +248,8 @@ nb.cluster.platform=\
         net.java.html.json,\
         net.java.html.sound,\
         netbinox,\
+        o.apache.commons.io,\
+        o.apache.commons.logging,\
         o.n.core,\
         o.n.html.ko4j,\
         o.n.html.xhr4j,\
@@ -270,6 +273,7 @@ nb.cluster.platform=\
         openide.options,\
         openide.text,\
         openide.util.enumerations,\
+        openide.util.ui.svg,\
         openide.windows,\
         options.api,\
         options.keymap,\
@@ -437,9 +441,7 @@ nb.cluster.ide=\
         notifications,\
         o.apache.commons.codec,\
         o.apache.commons.httpclient,\
-        o.apache.commons.io,\
         o.apache.commons.lang,\
-        o.apache.commons.logging,\
         o.apache.ws.commons.util,\
         o.apache.xml.resolver,\
         o.apache.xmlrpc,\
diff --git a/ide/o.apache.commons.io/external/commons-io-1.4-license.txt 
b/nbbuild/licenses/Apache-2.0-XML-Commons-APIs
similarity index 78%
copy from ide/o.apache.commons.io/external/commons-io-1.4-license.txt
copy to nbbuild/licenses/Apache-2.0-XML-Commons-APIs
index 9544faf..1f71363 100644
--- a/ide/o.apache.commons.io/external/commons-io-1.4-license.txt
+++ b/nbbuild/licenses/Apache-2.0-XML-Commons-APIs
@@ -1,11 +1,4 @@
-Name: Apache Commons IO
-Description: Assist with developing IO functionality
-Origin: Apache Software Foundation
-Version: 1.4
-License: Apache-2.0
-URL: http://commons.apache.org/io/
-
-
+======================  Parts of this work are licensed: ======================
 
                                  Apache License
                            Version 2.0, January 2004
@@ -209,3 +202,55 @@ URL: http://commons.apache.org/io/
    See the License for the specific language governing permissions and
    limitations under the License.
 
+======================  Parts of this work are licensed: ======================
+
+W3C® SOFTWARE NOTICE AND LICENSE
+Copyright © 2004 World Wide Web Consortium, (Massachusetts Institute of 
Technology,
+European Research Consortium for Informatics and Mathematics, Keio University).
+All Rights Reserved.
+
+The DOM bindings are published under the W3C Software Copyright Notice and
+License. The software license requires "Notice of any changes or modifications
+to the W3C files, including the date changes were made." Consequently, modified
+versions of the DOM bindings must document that they do not conform to the W3C
+standard; in the case of the IDL definitions, the pragma prefix can no longer
+be 'w3c.org'; in the case of the Java language binding, the package names can 
no
+longer be in the 'org.w3c' package.
+
+Note: The original version of the W3C Software Copyright Notice and License 
could
+be found at http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+This work (and included software, documentation such as READMEs, or other
+related items) is being provided by the copyright holders under the following
+license. By obtaining, using and/or copying this work, you (the licensee) agree
+that you have read, understood, and will comply with the following terms and
+conditions.
+
+Permission to copy, modify, and distribute this software and its documentation,
+with or without modification, for any purpose and without fee or royalty is
+hereby granted, provided that you include the following on ALL copies of the
+software and documentation or portions thereof, including modifications:
+
+  1. The full text of this NOTICE in a location viewable to users of the
+     redistributed or derivative work.
+  2. Any pre-existing intellectual property disclaimers, notices, or terms
+     and conditions. If none exist, the W3C Software Short Notice should be
+     included (hypertext is preferred, text is permitted) within the body
+     of any redistributed or derivative code.
+  3. Notice of any changes or modifications to the files, including the date
+     changes were made. (We recommend you provide URIs to the location from
+     which the code is derived.)
+
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE
+NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
+THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
+PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
+
+The name and trademarks of copyright holders may NOT be used in advertising or
+publicity pertaining to the software without specific, written prior 
permission.
+Title to copyright in this software and any associated documentation will at
+all times remain with copyright holders.
diff --git a/ide/o.apache.commons.io/build.xml 
b/platform/libs.batik.read/build.xml
similarity index 70%
copy from ide/o.apache.commons.io/build.xml
copy to platform/libs.batik.read/build.xml
index 5a07067..afa2656 100644
--- a/ide/o.apache.commons.io/build.xml
+++ b/platform/libs.batik.read/build.xml
@@ -19,7 +19,11 @@
     under the License.
 
 -->
-<project name="ide/o.apache.commons.io" default="build" basedir=".">
+
+<!-- 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.batik.read" default="build" basedir=".">
+    <description>Builds the Batik SVG reading library wrapper 
module.</description>
     <import file="../../nbbuild/templates/projectized.xml"/>
-    <target name="jar"/>
 </project>
diff --git 
a/ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt 
b/platform/libs.batik.read/external/batik-1.12-license.txt
similarity index 95%
copy from 
ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
copy to platform/libs.batik.read/external/batik-1.12-license.txt
index d68b66f..07d1a9b 100644
--- a/ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
+++ b/platform/libs.batik.read/external/batik-1.12-license.txt
@@ -1,9 +1,9 @@
-Name: Apache Jakarta Commons Logging
-Origin: Apache Software Foundation
-Version: 1.1.1
+Name: Apache Batik
+Version: 1.12
+Description: Batik is a toolkit for applications that want to use images in 
the Scalable Vector Graphics (SVG) format for various purposes, such as 
display, generation or manipulation.
 License: Apache-2.0
-Description: Logging component
-URL: http://commons.apache.org/logging/
+Origin: https://xmlgraphics.apache.org/batik/
+Files: batik-anim-1.12.jar, batik-awt-util-1.12.jar, batik-bridge-1.12.jar, 
batik-constants-1.12.jar, batik-css-1.12.jar, batik-dom-1.12.jar, 
batik-ext-1.12.jar, batik-gvt-1.12.jar, batik-i18n-1.12.jar, 
batik-parser-1.12.jar, batik-script-1.12.jar, batik-svg-dom-1.12.jar, 
batik-util-1.12.jar, batik-xml-1.12.jar
 
                                  Apache License
                            Version 2.0, January 2004
diff --git a/platform/libs.batik.read/external/batik-1.12-notice.txt 
b/platform/libs.batik.read/external/batik-1.12-notice.txt
new file mode 100644
index 0000000..f973b7c
--- /dev/null
+++ b/platform/libs.batik.read/external/batik-1.12-notice.txt
@@ -0,0 +1,18 @@
+Apache Batik
+Copyright 1999-2019 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This software contains code from the World Wide Web Consortium (W3C) for the 
+Document Object Model API (DOM API) and SVG Document Type Definition (DTD).
+
+This software contains code from the International Organisation for
+Standardization for the definition of character entities used in the software's
+documentation.
+
+This product includes images from the Tango Desktop Project
+(http://tango.freedesktop.org/).
+
+This product includes images from the Pasodoble Icon Theme
+(http://www.jesusda.com/projects/pasodoble).
diff --git a/platform/libs.batik.read/external/binaries-list 
b/platform/libs.batik.read/external/binaries-list
new file mode 100644
index 0000000..8e371c2
--- /dev/null
+++ b/platform/libs.batik.read/external/binaries-list
@@ -0,0 +1,34 @@
+# 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.
+
+639288C6A28F0EFCFEA84EBB17E50F189A22E3E8 org.apache.xmlgraphics:batik-anim:1.12
+652BADD31839669CFA5F01442F8569FBECD21E8F 
org.apache.xmlgraphics:batik-awt-util:1.12
+FBE0DDB2479947B626488A9782A6CF10358A5316 
org.apache.xmlgraphics:batik-bridge:1.12
+5B29253D1CFA01E04C69E7C28BB8300FEEA8CC56 
org.apache.xmlgraphics:batik-constants:1.12
+2BE539A021BFB638880A7394AD5D5A7403FBE3C9 org.apache.xmlgraphics:batik-css:1.12
+1F7A51F02419A5B20333EC8116382FD7BCA78BD5 org.apache.xmlgraphics:batik-dom:1.12
+A5850A5AE69A88EE18E961F8044DCBA452D26E8F org.apache.xmlgraphics:batik-ext:1.12
+C2B801412806277ADE24CAE0A2AF286523105D71 org.apache.xmlgraphics:batik-gvt:1.12
+06044C6026B1178C078371E271222455671B5BD7 org.apache.xmlgraphics:batik-i18n:1.12
+90BFC41579C890D543ACDB99B2B6390B09298B85 
org.apache.xmlgraphics:batik-parser:1.12
+1359DA49BDBF10786FC9CB592833DED11B97E432 
org.apache.xmlgraphics:batik-script:1.12
+CCC87493A4074348B2E090B2CE7A3ECCD4E8AF44 
org.apache.xmlgraphics:batik-svg-dom:1.12
+A6D07D042AE8C8343EADD125D9EB76E25FFD908A org.apache.xmlgraphics:batik-util:1.12
+104615BA0F67A463BB70E2638D87E158C882AE79 org.apache.xmlgraphics:batik-xml:1.12
+41A8B86B358E87F3F13CF46069721719105AFF66 xml-apis:xml-apis-ext:1.3.04
+8D261DF049A23D40A053D2700399EA76080FE0A8 
org.apache.xmlgraphics:xmlgraphics-commons:2.4
+
diff --git a/ide/o.apache.commons.io/external/commons-io-1.4-license.txt 
b/platform/libs.batik.read/external/xml-apis-ext-1.3.04-license.txt
similarity index 77%
copy from ide/o.apache.commons.io/external/commons-io-1.4-license.txt
copy to platform/libs.batik.read/external/xml-apis-ext-1.3.04-license.txt
index 9544faf..3c35073 100644
--- a/ide/o.apache.commons.io/external/commons-io-1.4-license.txt
+++ b/platform/libs.batik.read/external/xml-apis-ext-1.3.04-license.txt
@@ -1,11 +1,10 @@
-Name: Apache Commons IO
-Description: Assist with developing IO functionality
-Origin: Apache Software Foundation
-Version: 1.4
-License: Apache-2.0
-URL: http://commons.apache.org/io/
-
+Name: Apache XML Commons XML APIs
+Version: 1.3.04
+Description: Apache XML Graphics Commons is a library that consists of several 
reusable components used by Apache Batik and Apache FOP.
+License: Apache-2.0-XML-Commons-APIs
+Origin: https://xmlgraphics.apache.org/commons/
 
+======================  Parts of this work are licensed: ======================
 
                                  Apache License
                            Version 2.0, January 2004
@@ -209,3 +208,55 @@ URL: http://commons.apache.org/io/
    See the License for the specific language governing permissions and
    limitations under the License.
 
+======================  Parts of this work are licensed: ======================
+
+W3C® SOFTWARE NOTICE AND LICENSE
+Copyright © 2004 World Wide Web Consortium, (Massachusetts Institute of 
Technology,
+European Research Consortium for Informatics and Mathematics, Keio University).
+All Rights Reserved.
+
+The DOM bindings are published under the W3C Software Copyright Notice and
+License. The software license requires "Notice of any changes or modifications
+to the W3C files, including the date changes were made." Consequently, modified
+versions of the DOM bindings must document that they do not conform to the W3C
+standard; in the case of the IDL definitions, the pragma prefix can no longer
+be 'w3c.org'; in the case of the Java language binding, the package names can 
no
+longer be in the 'org.w3c' package.
+
+Note: The original version of the W3C Software Copyright Notice and License 
could
+be found at http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+This work (and included software, documentation such as READMEs, or other
+related items) is being provided by the copyright holders under the following
+license. By obtaining, using and/or copying this work, you (the licensee) agree
+that you have read, understood, and will comply with the following terms and
+conditions.
+
+Permission to copy, modify, and distribute this software and its documentation,
+with or without modification, for any purpose and without fee or royalty is
+hereby granted, provided that you include the following on ALL copies of the
+software and documentation or portions thereof, including modifications:
+
+  1. The full text of this NOTICE in a location viewable to users of the
+     redistributed or derivative work.
+  2. Any pre-existing intellectual property disclaimers, notices, or terms
+     and conditions. If none exist, the W3C Software Short Notice should be
+     included (hypertext is preferred, text is permitted) within the body
+     of any redistributed or derivative code.
+  3. Notice of any changes or modifications to the files, including the date
+     changes were made. (We recommend you provide URIs to the location from
+     which the code is derived.)
+
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE
+NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
+THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
+PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
+
+The name and trademarks of copyright holders may NOT be used in advertising or
+publicity pertaining to the software without specific, written prior 
permission.
+Title to copyright in this software and any associated documentation will at
+all times remain with copyright holders.
diff --git a/platform/libs.batik.read/external/xml-apis-ext-1.3.04-notice.txt 
b/platform/libs.batik.read/external/xml-apis-ext-1.3.04-notice.txt
new file mode 100644
index 0000000..dfd7644
--- /dev/null
+++ b/platform/libs.batik.read/external/xml-apis-ext-1.3.04-notice.txt
@@ -0,0 +1,10 @@
+Apache XML Commons XML APIs
+Copyright 2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+Portions of this software were originally based on the following:
+  - software copyright (c) 1999, IBM Corporation., http://www.ibm.com.
+  - software copyright (c) 1999, Sun Microsystems., http://www.sun.com.
+  - software copyright (c) 2000 World Wide Web Consortium, http://www.w3.org
diff --git 
a/ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt 
b/platform/libs.batik.read/external/xmlgraphics-commons-2.4-license.txt
similarity index 98%
copy from 
ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
copy to platform/libs.batik.read/external/xmlgraphics-commons-2.4-license.txt
index d68b66f..308dd56 100644
--- a/ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
+++ b/platform/libs.batik.read/external/xmlgraphics-commons-2.4-license.txt
@@ -1,9 +1,8 @@
-Name: Apache Jakarta Commons Logging
-Origin: Apache Software Foundation
-Version: 1.1.1
+Name: Apache XML Graphics Commons
+Version: 2.4
+Description: Apache XML Graphics Commons is a library that consists of several 
reusable components used by Apache Batik and Apache FOP.
 License: Apache-2.0
-Description: Logging component
-URL: http://commons.apache.org/logging/
+Origin: https://xmlgraphics.apache.org/commons/
 
                                  Apache License
                            Version 2.0, January 2004
diff --git 
a/platform/libs.batik.read/external/xmlgraphics-commons-2.4-notice.txt 
b/platform/libs.batik.read/external/xmlgraphics-commons-2.4-notice.txt
new file mode 100644
index 0000000..e8c8002
--- /dev/null
+++ b/platform/libs.batik.read/external/xmlgraphics-commons-2.4-notice.txt
@@ -0,0 +1,5 @@
+Apache XML Graphics Commons
+Copyright 2006-2019 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/platform/libs.batik.read/manifest.mf 
b/platform/libs.batik.read/manifest.mf
new file mode 100644
index 0000000..f3f7026
--- /dev/null
+++ b/platform/libs.batik.read/manifest.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.netbeans.libs.batik.read
+OpenIDE-Module-Implementation-Version: 1
+OpenIDE-Module-Localizing-Bundle: 
org/netbeans/libs/batik/read/Bundle.properties
+AutoUpdate-Show-In-Client: false
diff --git a/platform/libs.batik.read/nbproject/project.properties 
b/platform/libs.batik.read/nbproject/project.properties
new file mode 100644
index 0000000..5b10912
--- /dev/null
+++ b/platform/libs.batik.read/nbproject/project.properties
@@ -0,0 +1,56 @@
+# 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.batik-anim-1.12.jar=external/batik-anim-1.12.jar
+file.reference.batik-awt-util-1.12.jar=external/batik-awt-util-1.12.jar
+file.reference.batik-bridge-1.12.jar=external/batik-bridge-1.12.jar
+file.reference.batik-constants-1.12.jar=external/batik-constants-1.12.jar
+file.reference.batik-css-1.12.jar=external/batik-css-1.12.jar
+file.reference.batik-dom-1.12.jar=external/batik-dom-1.12.jar
+file.reference.batik-ext-1.12.jar=external/batik-ext-1.12.jar
+file.reference.batik-gvt-1.12.jar=external/batik-gvt-1.12.jar
+file.reference.batik-i18n-1.12.jar=external/batik-i18n-1.12.jar
+file.reference.batik-parser-1.12.jar=external/batik-parser-1.12.jar
+file.reference.batik-script-1.12.jar=external/batik-script-1.12.jar
+file.reference.batik-svg-dom-1.12.jar=external/batik-svg-dom-1.12.jar
+file.reference.batik-util-1.12.jar=external/batik-util-1.12.jar
+file.reference.batik-xml-1.12.jar=external/batik-xml-1.12.jar
+file.reference.xml-apis-ext-1.3.04.jar=external/xml-apis-ext-1.3.04.jar
+file.reference.xmlgraphics-commons-2.4.jar=external/xmlgraphics-commons-2.4.jar
+release.external/batik-anim-1.12.jar=modules/ext/batik-anim-1.12.jar
+release.external/batik-awt-util-1.12.jar=modules/ext/batik-awt-util-1.12.jar
+release.external/batik-bridge-1.12.jar=modules/ext/batik-bridge-1.12.jar
+release.external/batik-constants-1.12.jar=modules/ext/batik-constants-1.12.jar
+release.external/batik-css-1.12.jar=modules/ext/batik-css-1.12.jar
+release.external/batik-dom-1.12.jar=modules/ext/batik-dom-1.12.jar
+release.external/batik-ext-1.12.jar=modules/ext/batik-ext-1.12.jar
+release.external/batik-gvt-1.12.jar=modules/ext/batik-gvt-1.12.jar
+release.external/batik-i18n-1.12.jar=modules/ext/batik-i18n-1.12.jar
+release.external/batik-parser-1.12.jar=modules/ext/batik-parser-1.12.jar
+release.external/batik-script-1.12.jar=modules/ext/batik-script-1.12.jar
+release.external/batik-svg-dom-1.12.jar=modules/ext/batik-svg-dom-1.12.jar
+release.external/batik-util-1.12.jar=modules/ext/batik-util-1.12.jar
+release.external/batik-xml-1.12.jar=modules/ext/batik-xml-1.12.jar
+release.external/xml-apis-ext-1.3.04.jar=modules/ext/xml-apis-ext-1.3.04.jar
+release.external/xmlgraphics-commons-2.4.jar=modules/ext/xmlgraphics-commons-2.4.jar
+
+is.autoload=true
+javac.source=1.6
+
+nbm.homepage=https://xmlgraphics.apache.org/batik/
+sigtest.gen.fail.on.error=false
+spec.version.base=1.0.0
diff --git a/platform/libs.batik.read/nbproject/project.xml 
b/platform/libs.batik.read/nbproject/project.xml
new file mode 100644
index 0000000..8a7fa98
--- /dev/null
+++ b/platform/libs.batik.read/nbproject/project.xml
@@ -0,0 +1,203 @@
+<?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.batik.read</code-name-base>
+            <module-dependencies>
+                <!-- Use compile-dependency for these rather than
+                run-dependency, otherwise,
+                o.n.core.startup.layers.CachingPreventsFileTouchesTest will
+                fail with a "No reads during startup" error. Not sure why. The
+                test failure appears even if all the Batik JAR
+                class-path-extension dependencies are commented out, and if we
+                are only depending on org.apache.commons.logging. So the 
problem
+                is unrelated to Batik. -->
+                <dependency>
+                    <code-name-base>org.apache.commons.io</code-name-base>
+                    <compile-dependency/>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.apache.commons.logging</code-name-base>
+                    <compile-dependency/>
+                </dependency>
+            </module-dependencies>
+            <public-packages>
+                <!-- Just expose all packages from the wrapped JARs. -->
+                <package>org.apache.batik</package>
+                <package>org.apache.batik.anim</package>
+                <package>org.apache.batik.anim.dom</package>
+                <package>org.apache.batik.anim.timing</package>
+                <package>org.apache.batik.anim.values</package>
+                <package>org.apache.batik.bridge</package>
+                <package>org.apache.batik.bridge.svg12</package>
+                <package>org.apache.batik.constants</package>
+                <package>org.apache.batik.css.dom</package>
+                <package>org.apache.batik.css.engine</package>
+                <package>org.apache.batik.css.engine.sac</package>
+                <package>org.apache.batik.css.engine.value</package>
+                <package>org.apache.batik.css.engine.value.css2</package>
+                <package>org.apache.batik.css.engine.value.svg</package>
+                <package>org.apache.batik.css.engine.value.svg12</package>
+                <package>org.apache.batik.css.parser</package>
+                <package>org.apache.batik.dom</package>
+                <package>org.apache.batik.dom.events</package>
+                <package>org.apache.batik.dom.svg</package>
+                <package>org.apache.batik.dom.svg12</package>
+                <package>org.apache.batik.dom.traversal</package>
+                <package>org.apache.batik.dom.util</package>
+                <package>org.apache.batik.dom.xbl</package>
+                <package>org.apache.batik.ext.awt</package>
+                <package>org.apache.batik.ext.awt.color</package>
+                <package>org.apache.batik.ext.awt.font</package>
+                <package>org.apache.batik.ext.awt.g2d</package>
+                <package>org.apache.batik.ext.awt.geom</package>
+                <package>org.apache.batik.ext.awt.image</package>
+                <package>org.apache.batik.ext.awt.image.renderable</package>
+                <package>org.apache.batik.ext.awt.image.rendered</package>
+                <package>org.apache.batik.ext.awt.image.spi</package>
+                <package>org.apache.batik.ext.swing</package>
+                <package>org.apache.batik.gvt</package>
+                <package>org.apache.batik.gvt.event</package>
+                <package>org.apache.batik.gvt.filter</package>
+                <package>org.apache.batik.gvt.flow</package>
+                <package>org.apache.batik.gvt.font</package>
+                <package>org.apache.batik.gvt.renderer</package>
+                <package>org.apache.batik.gvt.text</package>
+                <package>org.apache.batik.i18n</package>
+                <package>org.apache.batik.parser</package>
+                <package>org.apache.batik.script</package>
+                <package>org.apache.batik.script.jpython</package>
+                <package>org.apache.batik.script.rhino</package>
+                <package>org.apache.batik.util</package>
+                <package>org.apache.batik.util.io</package>
+                <package>org.apache.batik.util.resources</package>
+                <package>org.apache.batik.w3c.dom</package>
+                <package>org.apache.batik.w3c.dom.events</package>
+                <package>org.apache.batik.xml</package>
+                <package>org.apache.xmlgraphics.fonts</package>
+                <package>org.apache.xmlgraphics.image</package>
+                <package>org.apache.xmlgraphics.image.codec.png</package>
+                <package>org.apache.xmlgraphics.image.codec.tiff</package>
+                <package>org.apache.xmlgraphics.image.codec.util</package>
+                <package>org.apache.xmlgraphics.image.loader</package>
+                <package>org.apache.xmlgraphics.image.loader.cache</package>
+                <package>org.apache.xmlgraphics.image.loader.impl</package>
+                
<package>org.apache.xmlgraphics.image.loader.impl.imageio</package>
+                <package>org.apache.xmlgraphics.image.loader.pipeline</package>
+                <package>org.apache.xmlgraphics.image.loader.spi</package>
+                <package>org.apache.xmlgraphics.image.loader.util</package>
+                <package>org.apache.xmlgraphics.image.rendered</package>
+                <package>org.apache.xmlgraphics.image.writer</package>
+                <package>org.apache.xmlgraphics.image.writer.imageio</package>
+                <package>org.apache.xmlgraphics.image.writer.internal</package>
+                <package>org.apache.xmlgraphics.io</package>
+                <package>org.apache.xmlgraphics.java2d</package>
+                <package>org.apache.xmlgraphics.java2d.color</package>
+                <package>org.apache.xmlgraphics.java2d.color.profile</package>
+                <package>org.apache.xmlgraphics.java2d.ps</package>
+                <package>org.apache.xmlgraphics.ps</package>
+                <package>org.apache.xmlgraphics.ps.dsc</package>
+                <package>org.apache.xmlgraphics.ps.dsc.events</package>
+                <package>org.apache.xmlgraphics.ps.dsc.tools</package>
+                <package>org.apache.xmlgraphics.util</package>
+                <package>org.apache.xmlgraphics.util.dijkstra</package>
+                <package>org.apache.xmlgraphics.util.i18n</package>
+                <package>org.apache.xmlgraphics.util.io</package>
+                <package>org.apache.xmlgraphics.util.uri</package>
+                <package>org.apache.xmlgraphics.xmp</package>
+                <package>org.apache.xmlgraphics.xmp.merge</package>
+                <package>org.apache.xmlgraphics.xmp.schemas</package>
+                <package>org.apache.xmlgraphics.xmp.schemas.pdf</package>
+                <package>org.w3c.css.sac</package>
+                <package>org.w3c.css.sac.helpers</package>
+                <package>org.w3c.dom.smil</package>
+                <package>org.w3c.dom.svg</package>
+            </public-packages>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-constants-1.12.jar</runtime-relative-path>
+                
<binary-origin>external/batik-constants-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-util-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-util-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-svg-dom-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-svg-dom-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-xml-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-xml-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-anim-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-anim-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-gvt-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-gvt-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-dom-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-dom-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-bridge-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-bridge-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-css-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-css-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-i18n-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-i18n-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-ext-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-ext-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-script-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-script-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/xmlgraphics-commons-2.4.jar</runtime-relative-path>
+                
<binary-origin>external/xmlgraphics-commons-2.4.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-parser-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-parser-1.12.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/xml-apis-ext-1.3.04.jar</runtime-relative-path>
+                <binary-origin>external/xml-apis-ext-1.3.04.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                
<runtime-relative-path>ext/batik-awt-util-1.12.jar</runtime-relative-path>
+                <binary-origin>external/batik-awt-util-1.12.jar</binary-origin>
+            </class-path-extension>
+        </data>
+    </configuration>
+</project>
diff --git a/ide/o.apache.commons.logging/nbproject/project.properties 
b/platform/libs.batik.read/src/org/netbeans/libs/batik/read/Bundle.properties
similarity index 73%
copy from ide/o.apache.commons.logging/nbproject/project.properties
copy to 
platform/libs.batik.read/src/org/netbeans/libs/batik/read/Bundle.properties
index 8788807..f99e527 100644
--- a/ide/o.apache.commons.logging/nbproject/project.properties
+++ 
b/platform/libs.batik.read/src/org/netbeans/libs/batik/read/Bundle.properties
@@ -14,5 +14,9 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-is.autoload=true
-nbm.module.author=Tomas Stupka
+
+
+OpenIDE-Module-Name=Batik SVG Reading Library
+OpenIDE-Module-Short-Description=Batik SVG Reading Library
+OpenIDE-Module-Long-Description=Contains the subset of JARs from the Apache 
Batik library necessary to read and paint SVG files.
+OpenIDE-Module-Display-Category=Libraries
diff --git a/ide/o.apache.commons.io/build.xml 
b/platform/o.apache.commons.io/build.xml
similarity index 92%
copy from ide/o.apache.commons.io/build.xml
copy to platform/o.apache.commons.io/build.xml
index 5a07067..70c3748 100644
--- a/ide/o.apache.commons.io/build.xml
+++ b/platform/o.apache.commons.io/build.xml
@@ -19,7 +19,7 @@
     under the License.
 
 -->
-<project name="ide/o.apache.commons.io" default="build" basedir=".">
+<project name="platform/o.apache.commons.io" default="build" basedir=".">
     <import file="../../nbbuild/templates/projectized.xml"/>
     <target name="jar"/>
 </project>
diff --git a/ide/o.apache.commons.io/external/binaries-list 
b/platform/o.apache.commons.io/external/binaries-list
similarity index 100%
rename from ide/o.apache.commons.io/external/binaries-list
rename to platform/o.apache.commons.io/external/binaries-list
diff --git a/ide/o.apache.commons.io/external/commons-io-1.4-license.txt 
b/platform/o.apache.commons.io/external/commons-io-1.4-license.txt
similarity index 100%
rename from ide/o.apache.commons.io/external/commons-io-1.4-license.txt
rename to platform/o.apache.commons.io/external/commons-io-1.4-license.txt
diff --git a/ide/o.apache.commons.io/external/commons-io-1.4-notice.txt 
b/platform/o.apache.commons.io/external/commons-io-1.4-notice.txt
similarity index 100%
rename from ide/o.apache.commons.io/external/commons-io-1.4-notice.txt
rename to platform/o.apache.commons.io/external/commons-io-1.4-notice.txt
diff --git a/ide/o.apache.commons.io/manifest.mf 
b/platform/o.apache.commons.io/manifest.mf
similarity index 100%
rename from ide/o.apache.commons.io/manifest.mf
rename to platform/o.apache.commons.io/manifest.mf
diff --git a/ide/o.apache.commons.io/nbproject/project.properties 
b/platform/o.apache.commons.io/nbproject/project.properties
similarity index 100%
rename from ide/o.apache.commons.io/nbproject/project.properties
rename to platform/o.apache.commons.io/nbproject/project.properties
diff --git a/ide/o.apache.commons.io/nbproject/project.xml 
b/platform/o.apache.commons.io/nbproject/project.xml
similarity index 100%
rename from ide/o.apache.commons.io/nbproject/project.xml
rename to platform/o.apache.commons.io/nbproject/project.xml
diff --git a/ide/o.apache.commons.logging/build.xml 
b/platform/o.apache.commons.logging/build.xml
similarity index 95%
rename from ide/o.apache.commons.logging/build.xml
rename to platform/o.apache.commons.logging/build.xml
index 9a1137c..ae93fd5 100644
--- a/ide/o.apache.commons.logging/build.xml
+++ b/platform/o.apache.commons.logging/build.xml
@@ -19,7 +19,7 @@
     under the License.
 
 -->
-<project name="ide/o.apache.commons.logging" default="build" basedir=".">
+<project name="platform/o.apache.commons.logging" default="build" basedir=".">
     <import file="../../nbbuild/templates/projectized.xml"/>
     <target name="jar" depends="-define-FileCRC32Calculator">
         <FileCRC32Calculator file="external/commons-logging-1.1.1.jar" 
property="o.apache.commons.logging.crc32" />
diff --git a/ide/o.apache.commons.logging/external/binaries-list 
b/platform/o.apache.commons.logging/external/binaries-list
similarity index 100%
rename from ide/o.apache.commons.logging/external/binaries-list
rename to platform/o.apache.commons.logging/external/binaries-list
diff --git 
a/ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt 
b/platform/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
similarity index 100%
rename from 
ide/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
rename to 
platform/o.apache.commons.logging/external/commons-logging-1.1.1-license.txt
diff --git 
a/ide/o.apache.commons.logging/external/commons-logging-1.1.1-notice.txt 
b/platform/o.apache.commons.logging/external/commons-logging-1.1.1-notice.txt
similarity index 100%
rename from 
ide/o.apache.commons.logging/external/commons-logging-1.1.1-notice.txt
rename to 
platform/o.apache.commons.logging/external/commons-logging-1.1.1-notice.txt
diff --git a/ide/o.apache.commons.logging/manifest.mf 
b/platform/o.apache.commons.logging/manifest.mf
similarity index 100%
rename from ide/o.apache.commons.logging/manifest.mf
rename to platform/o.apache.commons.logging/manifest.mf
diff --git a/ide/o.apache.commons.logging/nbproject/project.properties 
b/platform/o.apache.commons.logging/nbproject/project.properties
similarity index 100%
copy from ide/o.apache.commons.logging/nbproject/project.properties
copy to platform/o.apache.commons.logging/nbproject/project.properties
diff --git a/ide/o.apache.commons.logging/nbproject/project.xml 
b/platform/o.apache.commons.logging/nbproject/project.xml
similarity index 100%
rename from ide/o.apache.commons.logging/nbproject/project.xml
rename to platform/o.apache.commons.logging/nbproject/project.xml
diff --git 
a/platform/openide.actions/src/org/openide/resources/actions/redo.svg 
b/platform/openide.actions/src/org/openide/resources/actions/redo.svg
new file mode 100644
index 0000000..3df7e9b
--- /dev/null
+++ b/platform/openide.actions/src/org/openide/resources/actions/redo.svg
@@ -0,0 +1,82 @@
+<?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.
+
+-->
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 
6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"; [
+       <!ENTITY st0 "fill:#CAE3FF;">
+       <!ENTITY st1 "fill:#FAFAFA;">
+       <!ENTITY st2 "opacity:0.2;">
+       <!ENTITY st3 "opacity:0.03;">
+       <!ENTITY st4 "opacity:0.1;">
+       <!ENTITY st5 "opacity:0.15;">
+       <!ENTITY st6 "opacity:0.25;">
+       <!ENTITY st7 "fill:#FFFFFF;">
+       <!ENTITY st8 "opacity:0.45;">
+       <!ENTITY st9 "fill:#FFE1B0;">
+       <!ENTITY st10 "fill:#B3DBFF;">
+       <!ENTITY st11 "opacity:0.33;">
+       <!ENTITY st12 "fill:#FBDC7C;">
+       <!ENTITY st13 "fill:#FFDB43;">
+       <!ENTITY st14 "fill:#E79B00;">
+       <!ENTITY st15 "fill:#3883CE;">
+       <!ENTITY st16 
"fill:none;stroke:#003399;stroke-width:1.375;stroke-miterlimit:10;">
+       <!ENTITY st17 "fill:#E8513D;">
+       <!ENTITY st18 "fill:#1E1E1E;">
+       <!ENTITY st19 "fill:#FFC36D;">
+       <!ENTITY st20 "fill:#9FCBFF;">
+       <!ENTITY st21 "fill:#E9F7FF;">
+       <!ENTITY st22 "fill:#62707C;">
+       <!ENTITY st23 "fill:#7A8896;">
+       <!ENTITY st24 "fill:#57BFFF;">
+       <!ENTITY st25 "fill:#E69D35;">
+       <!ENTITY st26 "fill:#9CFF73;">
+       <!ENTITY st27 "fill:none;stroke:#000000;stroke-miterlimit:10;">
+       <!ENTITY st28 "fill:#4891CC;">
+       <!ENTITY st29 "fill:#474747;">
+       <!ENTITY st30 "fill:#CCA05E;">
+       <!ENTITY st31 "opacity:0.67;">
+       <!ENTITY st32 "opacity:0.3;">
+       <!ENTITY st33 "fill:#EAEAEA;">
+       <!ENTITY st34 "fill:#FFE945;">
+       <!ENTITY st35 "fill:#FFCF8C;">
+       <!ENTITY st36 "fill:#E2BF8E;">
+       <!ENTITY st37 "fill:#FF5252;">
+       <!ENTITY st38 "fill:#512EFF;">
+       <!ENTITY st39 "opacity:0.12;">
+       <!ENTITY st40 "fill:#45A5F4;">
+       <!ENTITY st41 "fill:url(#SVGID_1_);">
+       <!ENTITY st42 "fill:url(#SVGID_2_);">
+       <!ENTITY st43 
"fill:none;stroke:#000000;stroke-width:0.3359;stroke-miterlimit:10;">
+       <!ENTITY st44 "opacity:0.05;">
+]>
+<svg version="1.1" id="Vector_Icons" xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; x="0px"
+        y="0px" width="16px" height="16px" viewBox="0 0 16 16" 
style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+       <path style="&st24;" 
d="M6,10h10V0h-1l-3.05,3.05C10.683,1.783,8.933,1,7,1C3.134,1,0,4.134,0,8s3.134,7,7,7v-3.75
+               
c-1.795,0-3.25-1.455-3.25-3.25S5.205,4.75,7,4.75c0.897,0,1.71,0.364,2.298,0.952L6,9V10z"/>
+       <g style="&st11;">
+               <path 
d="M15,1.414V9H7.414l2.591-2.591l0.707-0.707l-0.707-0.707C9.202,4.192,8.135,3.75,7,3.75C4.656,3.75,2.75,5.656,2.75,8
+                       
c0,1.999,1.387,3.68,3.25,4.131v1.786C3.166,13.439,1,10.968,1,8c0-3.308,2.692-6,6-6c1.603,0,3.109,0.624,4.243,1.757
+                       l0.707,0.707l0.707-0.707L15,1.414 
M16,0h-1l-3.05,3.05C10.683,1.783,8.933,1,7,1C3.134,1,0,4.134,0,8s3.134,7,7,7v-3.75
+                       
c-1.795,0-3.25-1.455-3.25-3.25S5.205,4.75,7,4.75c0.897,0,1.71,0.364,2.298,0.952L6,9v1h10V0L16,0z"/>
+       </g>
+</g>
+</svg>
diff --git 
a/platform/openide.actions/src/org/openide/resources/actions/undo.svg 
b/platform/openide.actions/src/org/openide/resources/actions/undo.svg
new file mode 100644
index 0000000..e9b703e
--- /dev/null
+++ b/platform/openide.actions/src/org/openide/resources/actions/undo.svg
@@ -0,0 +1,82 @@
+<?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.
+
+-->
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 
6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"; [
+       <!ENTITY st0 "fill:#CAE3FF;">
+       <!ENTITY st1 "fill:#FAFAFA;">
+       <!ENTITY st2 "opacity:0.2;">
+       <!ENTITY st3 "opacity:0.03;">
+       <!ENTITY st4 "opacity:0.1;">
+       <!ENTITY st5 "opacity:0.15;">
+       <!ENTITY st6 "opacity:0.25;">
+       <!ENTITY st7 "fill:#FFFFFF;">
+       <!ENTITY st8 "opacity:0.45;">
+       <!ENTITY st9 "fill:#FFE1B0;">
+       <!ENTITY st10 "fill:#B3DBFF;">
+       <!ENTITY st11 "opacity:0.33;">
+       <!ENTITY st12 "fill:#FBDC7C;">
+       <!ENTITY st13 "fill:#FFDB43;">
+       <!ENTITY st14 "fill:#E79B00;">
+       <!ENTITY st15 "fill:#3883CE;">
+       <!ENTITY st16 
"fill:none;stroke:#003399;stroke-width:1.375;stroke-miterlimit:10;">
+       <!ENTITY st17 "fill:#E8513D;">
+       <!ENTITY st18 "fill:#1E1E1E;">
+       <!ENTITY st19 "fill:#FFC36D;">
+       <!ENTITY st20 "fill:#9FCBFF;">
+       <!ENTITY st21 "fill:#E9F7FF;">
+       <!ENTITY st22 "fill:#62707C;">
+       <!ENTITY st23 "fill:#7A8896;">
+       <!ENTITY st24 "fill:#57BFFF;">
+       <!ENTITY st25 "fill:#E69D35;">
+       <!ENTITY st26 "fill:#9CFF73;">
+       <!ENTITY st27 "fill:none;stroke:#000000;stroke-miterlimit:10;">
+       <!ENTITY st28 "fill:#4891CC;">
+       <!ENTITY st29 "fill:#474747;">
+       <!ENTITY st30 "fill:#CCA05E;">
+       <!ENTITY st31 "opacity:0.67;">
+       <!ENTITY st32 "opacity:0.3;">
+       <!ENTITY st33 "fill:#EAEAEA;">
+       <!ENTITY st34 "fill:#FFE945;">
+       <!ENTITY st35 "fill:#FFCF8C;">
+       <!ENTITY st36 "fill:#E2BF8E;">
+       <!ENTITY st37 "fill:#FF5252;">
+       <!ENTITY st38 "fill:#512EFF;">
+       <!ENTITY st39 "opacity:0.12;">
+       <!ENTITY st40 "fill:#45A5F4;">
+       <!ENTITY st41 "fill:url(#SVGID_1_);">
+       <!ENTITY st42 "fill:url(#SVGID_2_);">
+       <!ENTITY st43 
"fill:none;stroke:#000000;stroke-width:0.3359;stroke-miterlimit:10;">
+       <!ENTITY st44 "opacity:0.05;">
+]>
+<svg version="1.1" id="Vector_Icons" xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; x="0px"
+        y="0px" width="16px" height="16px" viewBox="0 0 16 16" 
style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+       <path style="&st25;" 
d="M10,10H0V0h1l3.05,3.05C5.317,1.783,7.067,1,9,1c3.866,0,7,3.134,7,7s-3.134,7-7,7v-3.75
+               
c1.795,0,3.25-1.455,3.25-3.25S10.795,4.75,9,4.75c-0.898,0-1.71,0.364-2.298,0.952L10,9V10z"/>
+       <g style="&st11;">
+               <path 
d="M1,1.414l2.343,2.343L4.05,4.464l0.707-0.707C5.891,2.624,7.397,2,9,2c3.308,0,6,2.692,6,6c0,2.968-2.166,5.439-5,5.917
+                       
v-1.786C11.863,11.68,13.25,9.999,13.25,8c0-2.344-1.907-4.25-4.25-4.25c-1.135,0-2.203,0.442-3.005,1.245L5.288,5.702
+                       l0.707,0.707L8.586,9H1V1.414 
M1,0H0v10h10V9L6.702,5.702C7.29,5.114,8.102,4.75,9,4.75c1.795,0,3.25,1.455,3.25,3.25
+                       
S10.795,11.25,9,11.25V15c3.866,0,7-3.134,7-7s-3.134-7-7-7C7.067,1,5.317,1.783,4.05,3.05L1,0L1,0z"/>
+       </g>
+</g>
+</svg>
diff --git a/ide/o.apache.commons.io/build.xml 
b/platform/openide.util.ui.svg/build.xml
similarity index 90%
rename from ide/o.apache.commons.io/build.xml
rename to platform/openide.util.ui.svg/build.xml
index 5a07067..a001567 100644
--- a/ide/o.apache.commons.io/build.xml
+++ b/platform/openide.util.ui.svg/build.xml
@@ -19,7 +19,7 @@
     under the License.
 
 -->
-<project name="ide/o.apache.commons.io" default="build" basedir=".">
+
+<project name="platform/openide.util.ui.svg" default="build" basedir=".">
     <import file="../../nbbuild/templates/projectized.xml"/>
-    <target name="jar"/>
 </project>
diff --git a/platform/openide.util.ui.svg/manifest.mf 
b/platform/openide.util.ui.svg/manifest.mf
new file mode 100644
index 0000000..2101cca
--- /dev/null
+++ b/platform/openide.util.ui.svg/manifest.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.openide.util.ui.svg
+OpenIDE-Module-Localizing-Bundle: org/openide/util/svg/Bundle.properties
+OpenIDE-Module-Specification-Version: 1.0
diff --git a/ide/o.apache.commons.logging/nbproject/project.properties 
b/platform/openide.util.ui.svg/nbproject/project.properties
similarity index 94%
copy from ide/o.apache.commons.logging/nbproject/project.properties
copy to platform/openide.util.ui.svg/nbproject/project.properties
index 8788807..0527df9 100644
--- a/ide/o.apache.commons.logging/nbproject/project.properties
+++ b/platform/openide.util.ui.svg/nbproject/project.properties
@@ -14,5 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-is.autoload=true
-nbm.module.author=Tomas Stupka
+
+javac.source=1.6
+javac.target=1.7
diff --git a/platform/openide.util.ui/nbproject/project.xml 
b/platform/openide.util.ui.svg/nbproject/project.xml
similarity index 56%
copy from platform/openide.util.ui/nbproject/project.xml
copy to platform/openide.util.ui.svg/nbproject/project.xml
index 1f9c6be..d0c8838 100644
--- a/platform/openide.util.ui/nbproject/project.xml
+++ b/platform/openide.util.ui.svg/nbproject/project.xml
@@ -23,9 +23,17 @@
     <type>org.netbeans.modules.apisupport.project</type>
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/nb-module-project/3";>
-            <code-name-base>org.openide.util.ui</code-name-base>
+            <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>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.util</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
@@ -34,6 +42,14 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.openide.util.ui</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.14</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.util.lookup</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
@@ -42,38 +58,7 @@
                     </run-dependency>
                 </dependency>
             </module-dependencies>
-            <test-dependencies>
-                <test-type>
-                    <name>unit</name>
-                    <test-dependency>
-                        
<code-name-base>org.netbeans.libs.junit4</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        
<code-name-base>org.netbeans.modules.nbjunit</code-name-base>
-                        <recursive/>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        
<code-name-base>org.openide.util.lookup</code-name-base>
-                        <compile-dependency/>
-                        <test/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.openide.util</code-name-base>
-                        <compile-dependency/>
-                        <test/>
-                    </test-dependency>
-                </test-type>
-            </test-dependencies>
-            <public-packages>
-                <package>org.openide</package>
-                <package>org.openide.util</package>
-                <package>org.openide.util.actions</package>
-                <package>org.openide.util.datatransfer</package>
-                <package>org.openide.util.io</package>
-                <package>org.openide.xml</package>
-            </public-packages>
+            <public-packages/>
         </data>
     </configuration>
 </project>
diff --git a/ide/o.apache.commons.logging/nbproject/project.properties 
b/platform/openide.util.ui.svg/src/org/openide/util/svg/Bundle.properties
similarity index 78%
rename from ide/o.apache.commons.logging/nbproject/project.properties
rename to 
platform/openide.util.ui.svg/src/org/openide/util/svg/Bundle.properties
index 8788807..5a9266d 100644
--- a/ide/o.apache.commons.logging/nbproject/project.properties
+++ b/platform/openide.util.ui.svg/src/org/openide/util/svg/Bundle.properties
@@ -14,5 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-is.autoload=true
-nbm.module.author=Tomas Stupka
+
+OpenIDE-Module-Name=SVG Loader
+OpenIDE-Module-Short-Description=SVG Loader
+OpenIDE-Module-Long-Description=Service provider for ImageUtilities' SVGLoader 
interface.
+OpenIDE-Module-Display-Category=Infrastructure
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
new file mode 100644
index 0000000..f6e0347
--- /dev/null
+++ b/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGIcon.java
@@ -0,0 +1,209 @@
+/*
+ * 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 java.awt.Component;
+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;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.util.LinkedHashMap;
+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.GVTBuilder;
+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.XMLResourceDescriptor;
+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.
+ * Thread-safe.
+ */
+final class SVGIcon extends CachedHiDPIIcon {
+    private static final Logger LOG = 
Logger.getLogger(SVGIcon.class.getName());
+    /* A limit of 8192 pixels on each side means the resulting maximum image 
buffer would take 268
+    megabytes. It's also twice twice as long as the longest side of a 4K 
display. This is small
+    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>()
+    {
+        @Override
+        protected SAXSVGDocumentFactory initialValue() {
+            return new 
SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
+        }
+    };
+
+    private final URL url;
+    /**
+     * Cache of the parsed SVG document. Just painting the GraphicsNode is 
much 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
+     * garbage collected after the first paint. The rasterized bitmap will be 
cached separately by
+     * the superclass.
+     */
+    private WeakReference<GraphicsNode> graphicsNodeWeakRef;
+    /**
+     * 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.
+     */
+    private GraphicsNode graphicsNodeStrongRef;
+
+    private SVGIcon(URL url, GraphicsNode initialGraphicsNode, int width, int 
height) {
+        super(width, height);
+        Parameters.notNull("url", url);
+        Parameters.notNull("initialGraphicsNode", initialGraphicsNode);
+        this.url = url;
+        this.graphicsNodeStrongRef = initialGraphicsNode;
+        this.graphicsNodeWeakRef = new 
WeakReference<GraphicsNode>(initialGraphicsNode);
+    }
+
+    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);
+    }
+
+    /**
+     * Get the {@code GraphicsNode}, 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();
+        if (ret != null) {
+            // Allow the GraphicsNode to be garbage collected after the 
initial paint.
+            graphicsNodeStrongRef = null;
+            return ret;
+        }
+        ret = loadGraphicsNode(url, null);
+        graphicsNodeWeakRef = new WeakReference<GraphicsNode>(ret);
+        return ret;
+    }
+
+    /**
+     * Load the original SVG resource.
+     *
+     * @param toSize if not null, will be set to the image's size
+     */
+    private static GraphicsNode loadGraphicsNode(URL url, Dimension toSize)
+            throws IOException
+    {
+        Parameters.notNull("url", url);
+        final GraphicsNode graphicsNode;
+        final Dimension2D documentSize;
+        final Document doc;
+        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);
+            UserAgent userAgent = new UserAgentAdapter();
+            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();
+            }
+        } catch (RuntimeException e) {
+            /* Rethrow the many different exceptions that can occur when 
parsing invalid SVG files;
+            DOMException, BridgeException etc. */
+            throw new IOException("Error parsing SVG file", e);
+        } finally {
+            is.close();
+        }
+        if (toSize != null) {
+            int width = (int) Math.ceil(documentSize.getWidth());
+            int height = (int) Math.ceil(documentSize.getHeight());
+            final int widthLimited = Math.min(MAX_DIMENSION_PIXELS, width);
+            final int heightLimited = Math.min(MAX_DIMENSION_PIXELS, height);
+            if (width != widthLimited || height != heightLimited) {
+                LOG.log(Level.WARNING,
+                        "SVG image {0} too large (dimensions were {1}x{2}, 
each side can be at most {3}px)",
+                        new Object[]{url, width, height, 
MAX_DIMENSION_PIXELS});
+            } else if (width <= 1 && height <= 1) {
+                LOG.log(Level.WARNING,
+                        "SVG image {0} did not specify a width/height, or is 
incorrectly sized", url);
+            }
+            toSize.width = widthLimited;
+            toSize.height = heightLimited;
+        }
+        return graphicsNode;
+    }
+
+    private static RenderingHints createHints() {
+        Map<RenderingHints.Key, Object> hints = new 
LinkedHashMap<RenderingHints.Key, Object>();
+        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. */
+        hints.put(RenderingHints.KEY_STROKE_CONTROL, 
RenderingHints.VALUE_STROKE_PURE);
+        return new RenderingHints(hints);
+    }
+
+    @Override
+    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);
+        try {
+            g.scale(scale, scale);
+            try {
+                GraphicsNode graphicsNode = getGraphicsNode();
+                g.addRenderingHints(createHints());
+                graphicsNode.paint(g);
+            } catch (IOException e) {
+                LOG.log(Level.WARNING,
+                        "Unexpected exception while re-loading an SVG file 
that previously loaded successfully", e);
+            }
+        } finally {
+            g.dispose();
+        }
+        return img;
+    }
+}
diff --git 
a/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGLoaderImpl.java 
b/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGLoaderImpl.java
new file mode 100644
index 0000000..27c25ab
--- /dev/null
+++ b/platform/openide.util.ui.svg/src/org/openide/util/svg/SVGLoaderImpl.java
@@ -0,0 +1,33 @@
+/*
+ * 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 java.io.IOException;
+import java.net.URL;
+import javax.swing.Icon;
+import org.openide.util.lookup.ServiceProvider;
+import org.openide.util.spi.SVGLoader;
+
+@ServiceProvider(service=SVGLoader.class)
+public class SVGLoaderImpl implements SVGLoader {
+  @Override
+  public Icon loadIcon(URL url) throws IOException {
+    return SVGIcon.load(url);
+  }
+}
diff --git a/platform/openide.util.ui/apichanges.xml 
b/platform/openide.util.ui/apichanges.xml
index 465346a..7505b6e 100644
--- a/platform/openide.util.ui/apichanges.xml
+++ b/platform/openide.util.ui/apichanges.xml
@@ -27,6 +27,33 @@
     <apidef name="actions">Actions API</apidef>
 </apidefs>
 <changes>
+    <change id="SVGLoader">
+      <api name="util"/>
+      <summary>Support loading of SVG icons for scalable rendering on HiDPI 
displays.</summary>
+      <version major="9" minor="15"/>
+      <date year="2019" month="11" day="24"/>
+      <author login="ebakke"/>
+      <compatibility addition="yes" binary="compatible" source="compatible" 
semantic="compatible"/>
+      <description>
+        <p>
+            As a part of the effort to make NetBeans look better on HiDPI 
displays, the
+            ImageUtilities class has now been completely updated to support 
scalable implementations
+            of the java.awt.Icon interface, and to support loading of icons 
and images from SVG
+            files. If an SVG file resource exists with the same base name as 
an existing bitmap
+            icon, the SVG file will be loaded instead (e.g. "icon.svg" will be 
loaded instead of
+            "icon.png"). SVG file resources can also be loaded explicitly.
+        </p>
+        <p>
+            To avoid bloating the core platform modules with large JAR 
libraries, the actual loading
+            and parsing of SVG files is implemented in a separate, optional 
module, which is lazily
+            loaded the first time that an SVG file is encountered for loading. 
A new interface
+            SVGLoader has been added to serve as an SPI for said module to 
implement. Furthermore,
+            the CachedHiDPIIcon helper class has been made public to assist in 
the implementation of
+            this and other scalable Icon implementations.
+        </p>
+      </description>
+      <issue number="NETBEANS-2604"/>
+    </change>
     <change id="VectorIcon">
       <api name="util"/>
       <summary>Added abstract class VectorIcon to support creation of 
custom-painted HiDPI icons.</summary>
diff --git a/platform/openide.util.ui/arch.xml 
b/platform/openide.util.ui/arch.xml
index 7203ae0..e23627c 100644
--- a/platform/openide.util.ui/arch.xml
+++ b/platform/openide.util.ui/arch.xml
@@ -51,7 +51,7 @@
  <answer id="arch-time">
   <p>
    The module has been around since 1997 and is still improved
-   from time to time.
+   from time to time. Support for HiDPI screens and SVG image loading was 
added in 2019.
   </p>
  </answer>
 
@@ -123,7 +123,10 @@
    a class that is looked up in <a 
href="@org-openide-util-lookup@/org/openide/util/Lookup.html#getDefault--">Lookup.getDefault()</a>
    and if registered can provide better UI elements for <a 
href="@JDK@/javax/swing/Action.html">Action</a>s.
    </api>
-   
+  </p>
+
+  <p>Support for SVG image loading can be enabled by including the optional
+     <a href="@org-openide-util-ui-svg@/overview-summary.html">SVG Loader</a> 
module.
   </p>
  </answer>
 
diff --git a/platform/openide.util.ui/nbproject/project.xml 
b/platform/openide.util.ui/nbproject/project.xml
index 1f9c6be..fa1cc44 100644
--- a/platform/openide.util.ui/nbproject/project.xml
+++ b/platform/openide.util.ui/nbproject/project.xml
@@ -69,6 +69,7 @@
             <public-packages>
                 <package>org.openide</package>
                 <package>org.openide.util</package>
+                <package>org.openide.util.spi</package>
                 <package>org.openide.util.actions</package>
                 <package>org.openide.util.datatransfer</package>
                 <package>org.openide.util.io</package>
diff --git a/platform/openide.util.ui/src/org/openide/util/CachedHiDPIIcon.java 
b/platform/openide.util.ui/src/org/openide/util/CachedHiDPIIcon.java
index b0bcffe..b9a0b9e 100644
--- a/platform/openide.util.ui/src/org/openide/util/CachedHiDPIIcon.java
+++ b/platform/openide.util.ui/src/org/openide/util/CachedHiDPIIcon.java
@@ -23,7 +23,10 @@ import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.GraphicsConfiguration;
 import java.awt.Image;
+import java.awt.Transparency;
 import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -35,7 +38,7 @@ import javax.swing.Icon;
  * representations for HiDPI displays. Bitmaps for multiple HiDPI scaling 
factors can be cached at
  * the same time, e.g. for multi-monitor setups. Thread-safe.
  */
-abstract class CachedHiDPIIcon implements Icon {
+public abstract class CachedHiDPIIcon implements Icon {
     /**
      * The maximum size of the cache, as a multiple of the size of the icon at 
100% scaling. For
      * example, storing three images at 100%, 150%, and 200% scaling, 
respectively, yields a total
@@ -56,7 +59,11 @@ abstract class CachedHiDPIIcon implements Icon {
     private double cacheSize = 0.0;
 
     /**
-     * Constructor to be used by subclasses.
+     * Constructor to be used by subclasses. For HiDPI screens, dimensions are 
specified in logical
+     * pixels rather than device pixels, as in the superclass.
+     *
+     * @param width the width of the icon
+     * @param height the height of the icon
      */
     protected CachedHiDPIIcon(int width, int height) {
         if (width < 0) {
@@ -78,7 +85,7 @@ abstract class CachedHiDPIIcon implements Icon {
         final int deviceWidth = (int) Math.ceil(getIconWidth() * scale);
         final int deviceHeight = (int) Math.ceil(getIconHeight() * scale);
         final Image img =
-                createImage(c, key.getGraphicsConfiguration(), deviceWidth, 
deviceHeight, scale);
+                createAndPaintImage(c, key.getColorModel(), deviceWidth, 
deviceHeight, scale);
         final double imgSize = key.getSize();
         if (imgSize <= MAX_CACHE_SIZE) {
             /* Evict least-recently-used images from the cache until we have 
space for the latest
@@ -133,7 +140,9 @@ abstract class CachedHiDPIIcon implements Icon {
     }
 
     /**
-     * Create a scaled image containing the graphics of this icon. The result 
may be cached.
+     * Create a scaled image containing the graphics of this icon. The result 
may be cached. The
+     * dimensions are specfied in device pixels rather than logical pixels, 
i.e. with HiDPI scaling
+     * applied.
      *
      * @param c the component that was passed to {@link 
Icon#paintIcon(Component,Graphics,int,int)}.
      *        The cache will <em>not</em> be invalidated if {@code c} or its 
state changes, so 
@@ -141,25 +150,51 @@ abstract class CachedHiDPIIcon implements Icon {
      *        ensure compatibility with existing Icon implementations that may 
be used as delegates.
      *        Future implementations might also elect to simply pass a dummy 
Component instance
      *        here.
-     * @param graphicsConfiguration the configuration of the surface on which 
the image will be
-     *        painted
-     * @param deviceWidth the required width of the image, with scaling 
already applied
-     * @param deviceHeight the required height of the image, with scaling 
already applied
+     * @param colorModel the {@link ColorModel} of the surface on which the 
image will be painted
+     *        (may be passed to {@link #createBufferedImage(ColorModel, int, 
int)} in the common
+     *        case)
+     * @param deviceWidth the required width of the image, in device pixels
+     * @param deviceHeight the required height of the image, in device pixels
      * @param scale the HiDPI scaling factor detected in {@code 
graphicsConfiguration}
      */
-    protected abstract Image createImage(Component c, GraphicsConfiguration 
graphicsConfiguration,
+    protected abstract Image createAndPaintImage(Component c, ColorModel 
colorModel,
             int deviceWidth, int deviceHeight, double scale);
 
+    /**
+     * Utility method to create a compatible {@link BufferedImage} from the 
parameters passed to
+     * {@link #createAndPaintImage(Component, ColorModel, int, int, double)}. 
May be called by
+     * implementors of the latter to create a surface to draw on and return.
+     *
+     * @param colorModel the required {@link ColorModel}
+     * @param deviceWidth the required width of the image, in device pixels
+     * @param deviceHeight the required height of the image, in device pixels
+     * @return an image compatible with the given parameters
+     */
+    protected static final BufferedImage createBufferedImage(
+            ColorModel colorModel, int deviceWidth, int deviceHeight)
+    {
+      return new BufferedImage(
+          colorModel,
+          colorModel.createCompatibleWritableRaster(deviceWidth, deviceHeight),
+          colorModel.isAlphaPremultiplied(), null);
+    }
+
+    /**
+     * Key for image cache map. Immutable.
+     */
     private static final class CachedImageKey {
-        private final GraphicsConfiguration gconf;
+        /* The ColorModel is the only field in GraphicsConfiguration that is 
needed to create a
+        compatible BufferedImage. So include only that one, plus the HiDPI 
scaling factor, in the
+        cache key. */
+        private final ColorModel colorModel;
         private final double scale;
 
-        public CachedImageKey(GraphicsConfiguration gconf, double scale) {
-            Parameters.notNull("gconf", gconf);
+        private CachedImageKey(ColorModel colorModel, double scale) {
+            Parameters.notNull("colorModel", colorModel);
             if (scale <= 0.0) {
                 throw new IllegalArgumentException();
             }
-            this.gconf = gconf;
+            this.colorModel = colorModel;
             this.scale = scale;
         }
 
@@ -174,7 +209,12 @@ abstract class CachedHiDPIIcon implements Icon {
             } else {
                 scale = 1.0;
             }
-            return new CachedImageKey(g.getDeviceConfiguration(), scale);
+            GraphicsConfiguration gconf = g.getDeviceConfiguration();
+            /* Always use the same transparency mode for the cached images, so 
we don't end up with
+            one set of cached images for each encountered mode. The 
TRANSLUCENT mode is the most
+            generic one; presumably it should paint OK onto less capable 
surfaces. */
+            ColorModel colorModel = 
gconf.getColorModel(Transparency.TRANSLUCENT);
+            return new CachedImageKey(colorModel, scale);
         }
 
         public double getScale() {
@@ -188,13 +228,13 @@ abstract class CachedHiDPIIcon implements Icon {
             return Math.pow(getScale(), 2.0);
         }
 
-        public GraphicsConfiguration getGraphicsConfiguration() {
-            return gconf;
+        public ColorModel getColorModel() {
+            return colorModel;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(gconf, scale);
+            return Objects.hash(colorModel, scale);
         }
 
         @Override
@@ -203,8 +243,13 @@ abstract class CachedHiDPIIcon implements Icon {
                 return false;
             }
             final CachedImageKey other = (CachedImageKey) obj;
-            return this.gconf.equals(other.gconf) &&
+            return this.colorModel.equals(other.colorModel) &&
                    this.scale == other.scale;
         }
+
+        @Override
+        public String toString() {
+            return "CachedImageKey(" + colorModel + ", " + scale + ")";
+        }
     }
 }
diff --git a/platform/openide.util.ui/src/org/openide/util/FilteredIcon.java 
b/platform/openide.util.ui/src/org/openide/util/FilteredIcon.java
index 0496c3b..6e0c52c 100644
--- a/platform/openide.util.ui/src/org/openide/util/FilteredIcon.java
+++ b/platform/openide.util.ui/src/org/openide/util/FilteredIcon.java
@@ -21,12 +21,11 @@ package org.openide.util;
 import java.awt.Component;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
 import java.awt.Image;
 import java.awt.Rectangle;
 import java.awt.Toolkit;
-import java.awt.Transparency;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
 import java.awt.image.FilteredImageSource;
 import java.awt.image.RGBImageFilter;
 import javax.swing.Icon;
@@ -59,12 +58,10 @@ final class FilteredIcon extends CachedHiDPIIcon {
     }
 
     @Override
-    protected Image createImage(
-            Component c, GraphicsConfiguration graphicsConfiguration,
-            int deviceWidth, int deviceHeight, double scale)
+    protected Image createAndPaintImage(
+            Component c, ColorModel colorModel, int deviceWidth, int 
deviceHeight, double scale)
     {
-        final BufferedImage img = graphicsConfiguration.createCompatibleImage(
-                deviceWidth, deviceHeight, Transparency.TRANSLUCENT);
+        final BufferedImage img = createBufferedImage(colorModel, deviceWidth, 
deviceHeight);
         final Graphics2D imgG = img.createGraphics();
         try {
             imgG.clip(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
diff --git a/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java 
b/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java
index 4af5cc8..e9d90b1 100644
--- a/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java
+++ b/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java
@@ -23,7 +23,6 @@ import java.awt.Component;
 import java.awt.EventQueue;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
 import java.awt.HeadlessException;
 import java.awt.Image;
 import java.awt.MediaTracker;
@@ -45,7 +44,9 @@ import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javax.imageio.ImageIO;
@@ -57,6 +58,7 @@ import javax.swing.ImageIcon;
 import javax.swing.JLabel;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
+import org.openide.util.spi.SVGLoader;
 
 /** 
  * Useful static methods for manipulation with images/icons, results are 
cached.
@@ -91,9 +93,10 @@ public final class ImageUtilities {
      * @see "#20072"
      */
     private static final Set<String> extraInitialSlashes = new 
HashSet<String>();
-    private static volatile Object currentLoader;
-    private static Lookup.Result<ClassLoader> loaderQuery = null;
-    private static boolean noLoaderWarned = false;
+    private static final CachedLookupLoader<ClassLoader> classLoaderLoader =
+            new CachedLookupLoader<ClassLoader>(ClassLoader.class);
+    private static final CachedLookupLoader<SVGLoader> svgLoaderLoader =
+            new CachedLookupLoader<SVGLoader>(SVGLoader.class);
     private static final Component component = new Component() {
     };
 
@@ -101,7 +104,6 @@ public final class ImageUtilities {
     private static int mediaTrackerID;
     
     private static ImageReader PNG_READER;
-//    private static ImageReader GIF_READER;
     
     private static final Logger ERR = 
Logger.getLogger(ImageUtilities.class.getName());
     
@@ -110,7 +112,7 @@ public final class ImageUtilities {
     /**
      * Dummy component to be passed to the first parameter  of
      * {@link Icon#paintIcon(Component, Graphics, int, int)} when converting 
an {@code Icon} to an
-     * {@code Image}. See comment in {@link #icon2ToolTipImage(Icon)}.
+     * {@code Image}. See comment in {@link #icon2ToolTipImage(Icon, URL)}.
      */
     private static volatile Component dummyIconComponent;
 
@@ -135,12 +137,25 @@ public final class ImageUtilities {
     static {
         ImageIO.setUseCache(false);
         PNG_READER = ImageIO.getImageReadersByMIMEType("image/png").next();
-//        GIF_READER = ImageIO.getImageReadersByMIMEType("image/gif").next();
     }
 
     /**
      * Loads an image from the specified resource ID. The image is loaded 
using the "system" classloader registered in
      * Lookup.
+     *
+     * <p>If the default lookup contains a service provider for the {@link 
SVGLoader} interface, and
+     * there exists an SVG version of the requested image (e.g. "icon.svg" 
exists when "icon.png"
+     * was requested), the SVG version will be loaded instead of the 
originally requested bitmap.
+     * SVG images can also be requested directly. The SVG document's root 
element must contain
+     * explicit width/height attributes. An SVG loader implementation can be 
installed via the
+     * optional {@code openide.util.ui.svg} module.
+     *
+     * <p>To paint SVG images at arbitrary resolutions, convert the returned 
{@link Image} to an
+     * {@link Icon} using {@link #image2Icon(Image)}, and set an appropriate 
transform on the
+     * {@link Graphics2D} instance passed to {@link Icon#paintIcon(Component, 
Graphics, int, int)}.
+     * When painting on HiDPI-capable {@code Graphics2D} instances provided by 
Swing, the
+     * appropriate transform will already be in place.
+     *
      * @param resourceID resource path of the icon (no initial slash)
      * @return icon's Image, or null, if the icon cannot be loaded.     
      */
@@ -191,7 +206,7 @@ public final class ImageUtilities {
             // only non _dark images need filtering
             RGBImageFilter imageFilter = getImageIconFilter();
             if (null != image && null != imageFilter) {
-                image = icon2ToolTipImage(FilteredIcon.create(imageFilter, 
image));
+                image = icon2ToolTipImage(FilteredIcon.create(imageFilter, 
image), image.url);
             }
         }
         return image;
@@ -315,15 +330,18 @@ public final class ImageUtilities {
             if (ret != null)
                 return ret;
         }
-        return icon2ToolTipImage(icon);
+        return icon2ToolTipImage(icon, null);
     }
 
-    private static ToolTipImage icon2ToolTipImage(Icon icon) {
+    /**
+     * @param url may be null
+     */
+    private static ToolTipImage icon2ToolTipImage(Icon icon, URL url) {
         Parameters.notNull("icon", icon);
         if (icon instanceof ToolTipImage) {
             return (ToolTipImage) icon;
         }
-        ToolTipImage image = new ToolTipImage(icon, "", 
BufferedImage.TYPE_INT_ARGB);
+        ToolTipImage image = new ToolTipImage(icon, "", url, 
BufferedImage.TYPE_INT_ARGB);
         Graphics g = image.getGraphics();
         /* Previously, we'd create a new JLabel here every time; this once led 
to a deadlock on
         startup when the nb.imageicon.filter setting was enabled. The 
underlying problem is that
@@ -428,47 +446,107 @@ public final class ImageUtilities {
     }
 
     /**
+     * Get an SVG icon loader, if the appropriate service provider module is 
installed. To ensure
+     * lazy loading of the SVG loader module, this method should only be 
called when there actually
+     * exists an SVG file to load. The result is cached.
+     *
+     * @return may be null
+     */
+    private static SVGLoader getSVGLoader() {
+        /* "Objects contained in the default lookup are instantiated lazily 
when first requested."
+        ( http://wiki.netbeans.org/DevFaqLookupDefault ) So the SVGLoader 
implementation module will
+        only be loaded the first time an SVG file is actually encountered for 
loading, rather than,
+        for instance, when the startup splash screen initializes 
ImageUtilities to load its PNG
+        image. This was confirmed by printing a debugging message from a 
static initializer in
+        SVGLoaderImpl in the implementation module; the message appears well 
after the splash
+        screen's PNG graphics first becomes visible. */
+        return svgLoaderLoader.getLoader();
+    }
+
+    /**
      * Get the class loader from lookup.
      * Since this is done very frequently, it is wasteful to query lookup each 
time.
      * Instead, remember the last result and just listen for changes.
      */
-    static ClassLoader getLoader() {
-        Object is = currentLoader;
-        if (is instanceof ClassLoader) {
-            return (ClassLoader)is;
-        }
-            
-        currentLoader = Thread.currentThread();
-            
-        if (loaderQuery == null) {
-            loaderQuery = Lookup.getDefault().lookup(new 
Lookup.Template<ClassLoader>(ClassLoader.class));
-            loaderQuery.addLookupListener(
-                new LookupListener() {
-                    public void resultChanged(LookupEvent ev) {
-                        ERR.fine("Loader cleared"); // NOI18N
-                        currentLoader = null;
-                    }
-                }
-            );
+    static ClassLoader getClassLoader() {
+        return classLoaderLoader.getLoader();
+    }
+
+    private static final class CachedLookupLoader<T> {
+        private final Class<T> clazz;
+        private final AtomicBoolean noLoaderWarned = new AtomicBoolean(false);
+        /**
+         * Cached result of {@link #getLoader()}. Null means the cache is 
cleared; absent means the
+         * result is cached but was null (no loader found). This field is 
marked volatile so that it
+         * can be retrieved without synchronization in the common case, like 
in prior versions.
+         */
+        private volatile Optional<T> currentLoader;
+        /**
+         * The thread which last started performing an uncached lookup, when 
said lookup is
+         * currently in progress. The result of an uncached lookup will only 
be cached if
+         * (1) LookupListener.resultChanged was _not_ called while the lookup 
was being performed
+         * and (2) no other uncached lookups were started more recently. This 
is slightly cleaned-up
+         * version of the fix for an old race condition bug (#62194 in 
BugZilla).
+         */
+        private Thread threadInProgress;
+        private Lookup.Result<T> loaderQuery;
+
+        public CachedLookupLoader(Class<T> clazz) {
+            Parameters.notNull("clazz", clazz);
+            this.clazz = clazz;
         }
 
-        Iterator it = loaderQuery.allInstances().iterator();
-        if (it.hasNext()) {
-            ClassLoader toReturn = (ClassLoader) it.next();
-            if (currentLoader == Thread.currentThread()) {
-                currentLoader = toReturn;
+        public T getLoader() {
+            Optional<T> toReturn = currentLoader;
+            if (toReturn != null) {
+                return toReturn.orElse(null);
             }
-            if (ERR.isLoggable(Level.FINE)) {
-                ERR.fine("Loader computed: " + currentLoader); // NOI18N
+            final Lookup.Result<T> useLoaderQuery;
+            synchronized (this) {
+                // Signal to other threads that their result is outdated.
+                threadInProgress = Thread.currentThread();
+                if (loaderQuery == null) {
+                    loaderQuery = Lookup.getDefault().lookupResult(clazz);
+                    loaderQuery.addLookupListener(
+                        new LookupListener() {
+                            @Override
+                            public void resultChanged(LookupEvent ev) {
+                                ERR.log(Level.FINE, "Loader for {0} cleared", 
clazz); // NOI18N
+                                /* Clear any existing cached result, and 
indicate to ongoing lookup
+                                operations in other threads that their results 
are outdated and
+                                should not be cahced. */
+                                synchronized (CachedLookupLoader.this) {
+                                    currentLoader = null;
+                                    threadInProgress = null;
+                                }
+                            }
+                        }
+                    );
+                }
+                useLoaderQuery = loaderQuery;
             }
-            return toReturn;
-        } else { if (!noLoaderWarned) {
-                noLoaderWarned = true;
-                ERR.warning(
-                    "No ClassLoader instance found in " + Lookup.getDefault() 
// NOI18N
-                );
+            Iterator it = useLoaderQuery.allInstances().iterator();
+            toReturn = Optional.ofNullable(it.hasNext() ? (T) it.next() : 
null);
+            if (!toReturn.isPresent()) {
+                if (!noLoaderWarned.getAndSet(true)) {
+                    ERR.log(Level.WARNING, "No {0} instance found in {1}", // 
NOI18N
+                            new Object[]{ clazz, Lookup.getDefault() });
+                }
+            } else if (ERR.isLoggable(Level.FINE)) {
+                // Log message must start with "Loader computed", per 
ImageUtilitiesGetLoaderTest.
+                ERR.log(Level.FINE, "Loader computed for {0}: {1}", // NOI18N
+                        new Object[]{ clazz, toReturn.orElse(null) });
             }
-            return null;
+            synchronized (this) {
+                if (threadInProgress == Thread.currentThread()) {
+                    /* We're the last thread to have started performing a 
lookup, and the result has
+                    not been invalidated since after we started the operation, 
so we can safely
+                    cache the result. */
+                    threadInProgress = null;
+                    currentLoader = toReturn;
+                }
+            }
+            return toReturn.orElse(null);
         }
     }
 
@@ -497,7 +575,7 @@ public final class ImageUtilities {
                 }
 
                 // find localized or base image
-                ClassLoader loader = getLoader();
+                ClassLoader loader = getClassLoader();
 
                 // we'll keep the String probably for long time, optimize it
                 resource = new String(resource).intern(); // NOPMD
@@ -538,7 +616,7 @@ public final class ImageUtilities {
                 return null;
             }
         } else {
-            return getIcon(resource, getLoader(), false);
+            return getIcon(resource, getClassLoader(), false);
         }
     }
 
@@ -600,15 +678,39 @@ public final class ImageUtilities {
                 n = name;
             }
 
-            // we have to load it
-            java.net.URL url = (loader != null) ? loader.getResource(n)
-                                                : 
ImageUtilities.class.getClassLoader().getResource(n);
+            // Load the icon.
+            SVGLoader svgLoader = null; // If not null, url should be loaded 
as an SVG file.
+            ClassLoader useClassLoader =
+                    (loader != null) ? loader : 
ImageUtilities.class.getClassLoader();
+            java.net.URL url = null;
+            if (n.endsWith(".png") || n.endsWith(".gif") || 
n.endsWith(".svg")) {
+                /* If an SVG version of the image is available, always load 
that one. Only attempt
+                to load the SVGLoader implementation module if an actual SVG 
file exists. */
+                URL svgURL = useClassLoader.getResource(n.substring(0, 
n.length() - 4) + ".svg");
+                if (svgURL != null) {
+                    svgLoader = getSVGLoader();
+                    if (svgLoader != null) {
+                        url = svgURL;
+                    } else {
+                        ERR.log(Level.INFO, "No SVG loader available for 
loading {0}", svgURL);
+                    }
+                }
+            }
+            if (url == null && !n.endsWith(".svg")) { // The SVG case was 
handled before.
+                url = useClassLoader.getResource(n);
+            }
 
 //            img = (url == null) ? null : 
Toolkit.getDefaultToolkit().createImage(url);
             Image result = null;
             try {
                 if (url != null) {
-                    if (name.endsWith(".png")) {
+                    if (svgLoader != null) {
+                        try {
+                            result = 
icon2ToolTipImage(svgLoader.loadIcon(url), url);
+                        } catch (IOException e) {
+                            ERR.log(Level.INFO, "Failed to load SVG image " + 
url, e);
+                        }
+                    } else if (name.endsWith(".png")) {
                         ImageInputStream stream = 
ImageIO.createImageInputStream(url.openStream());
                         ImageReadParam param = 
PNG_READER.getDefaultReadParam();
                         try {
@@ -620,20 +722,6 @@ public final class ImageUtilities {
                         }
                         stream.close();
                     } 
-                    /*
-                    else if (name.endsWith(".gif")) {
-                        ImageInputStream stream = 
ImageIO.createImageInputStream(url.openStream());
-                        ImageReadParam param = 
GIF_READER.getDefaultReadParam();
-                        try {
-                            GIF_READER.setInput(stream, true, true);
-                            result = GIF_READER.read(0, param);
-                        }
-                        catch (IOException ioe1) {
-                            ERR.log(Level.INFO, "Image "+name+" is not GIF", 
ioe1);
-                        }
-                        stream.close();
-                    }
-                     */
 
                     if (result == null) {
                         result = ImageIO.read(url);
@@ -657,7 +745,9 @@ public final class ImageUtilities {
                     ERR.log(Level.FINE, "loading icon {0} = {1}", new Object[] 
{n, result});
                 }
                 name = new String(name).intern(); // NOPMD
-                ToolTipImage toolTipImage = ToolTipImage.createNew("", result, 
url);
+                ToolTipImage toolTipImage = (result instanceof ToolTipImage)
+                        ? (ToolTipImage) result
+                        : ToolTipImage.createNew("", result, url);
                 cache.put(name, new ActiveRef<String>(toolTipImage, cache, 
name));
                 return toolTipImage;
             } else { // no icon found
@@ -669,10 +759,11 @@ public final class ImageUtilities {
         }
     }
 
+    // Note: No longer in use.
     /** The method creates a BufferedImage which represents the same Image as 
the
      * parameter but consumes less memory.
      */
-    static final Image toBufferedImage(Image img) {
+    private static final Image toBufferedImage(Image img) {
         // load the image
         new javax.swing.ImageIcon(img, "");
 
@@ -766,11 +857,10 @@ public final class ImageUtilities {
         }
 
         @Override
-        protected Image createImage(Component c, GraphicsConfiguration 
graphicsConfiguration,
-                int deviceWidth, int deviceHeight, double scale)
+        protected Image createAndPaintImage(
+                Component c, ColorModel colorModel, int deviceWidth, int 
deviceHeight, double scale)
         {
-            BufferedImage ret = graphicsConfiguration.createCompatibleImage(
-                    deviceWidth, deviceHeight, Transparency.TRANSLUCENT);
+            BufferedImage ret = createBufferedImage(colorModel, deviceWidth, 
deviceHeight);
             Graphics2D g = ret.createGraphics();
             try {
                 g.clip(new Rectangle(0, 0, deviceWidth, deviceHeight));
@@ -941,6 +1031,7 @@ public final class ImageUtilities {
         final String toolTipText;
         // May be null.
         final Icon delegateIcon;
+        // May be null.
         final URL url;
         // May be null.
         ImageIcon imageIconVersion;
@@ -987,13 +1078,16 @@ public final class ImageUtilities {
           return imageIconVersion;
         }
 
-        public ToolTipImage(Icon delegateIcon, String toolTipText, int 
imageType) {
+        /**
+         * @param url may be null
+         */
+        public ToolTipImage(Icon delegateIcon, String toolTipText, URL url, 
int imageType) {
             // BufferedImage must have width/height > 0.
             super(Math.max(1, delegateIcon.getIconWidth()),
                     Math.max(1, delegateIcon.getIconHeight()), imageType);
             this.delegateIcon = delegateIcon;
             this.toolTipText = toolTipText;
-            this.url = null;
+            this.url = url;
         }
 
         /**
diff --git a/platform/openide.util.ui/src/org/openide/util/spi/SVGLoader.java 
b/platform/openide.util.ui/src/org/openide/util/spi/SVGLoader.java
new file mode 100644
index 0000000..09608f0
--- /dev/null
+++ b/platform/openide.util.ui/src/org/openide/util/spi/SVGLoader.java
@@ -0,0 +1,40 @@
+/*
+ * 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.spi;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.swing.Icon;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ * SVG image loader. This is an optional service provider. If implemented, a 
single instance should
+ * be placed in the default lookup (e.g. via the {@link ServiceProvider} 
annotation).
+ */
+public interface SVGLoader {
+    /**
+     * Load an SVG image as an {@link Icon}. The SVG document's root element 
must contain explicit
+     * width/height attributes.
+     *
+     * @param url may not be null
+     * @return may not be null
+     * @throws IOException in case of loading or parsing errors
+     */
+    public Icon loadIcon(URL url) throws IOException;
+}
diff --git 
a/platform/openide.util.ui/test/unit/src/org/openide/util/ImageUtilitiesGetLoaderTest.java
 
b/platform/openide.util.ui/test/unit/src/org/openide/util/ImageUtilitiesGetLoaderTest.java
index 4353714..ae163a1 100644
--- 
a/platform/openide.util.ui/test/unit/src/org/openide/util/ImageUtilitiesGetLoaderTest.java
+++ 
b/platform/openide.util.ui/test/unit/src/org/openide/util/ImageUtilitiesGetLoaderTest.java
@@ -54,11 +54,11 @@ public class ImageUtilitiesGetLoaderTest extends TestCase {
     }
 
     public void testWrongImplOfGetLoaderIssue62194() throws Exception {
-        ClassLoader l = ImageUtilities.getLoader ();
+        ClassLoader l = ImageUtilities.getClassLoader ();
         assertTrue("Error manager race condition activated", 
ErrMgr.switchDone);
         assertEquals("c1 the original one", Lkp.c1, l);
         
-        ClassLoader n = ImageUtilities.getLoader ();
+        ClassLoader n = ImageUtilities.getClassLoader ();
         assertEquals("c2 the new one", Lkp.c2, n);
     }
     
diff --git 
a/webcommon/javascript.nodejs/src/org/netbeans/modules/javascript/nodejs/ui/resources/npm.svg
 
b/webcommon/javascript.nodejs/src/org/netbeans/modules/javascript/nodejs/ui/resources/npm.svg
index b350d68..310d12e 100644
--- 
a/webcommon/javascript.nodejs/src/org/netbeans/modules/javascript/nodejs/ui/resources/npm.svg
+++ 
b/webcommon/javascript.nodejs/src/org/netbeans/modules/javascript/nodejs/ui/resources/npm.svg
@@ -28,4 +28,4 @@
 - the file was opened, color was modified to #CC3534 and saved with NetBeans
 - color was taken from here: https://www.schemecolor.com/npm-logo-colors.php
 -->
-<svg role="img" viewBox="0 0 24 24" fill="#CC3534" 
xmlns="http://www.w3.org/2000/svg";><title>NPM icon</title><path d="M0 
7.334v8h6.666v1.332H12v-1.332h12v-8H0zm6.666 
6.664H5.334v-4H3.999v4H1.335V8.667h5.331v5.331zm4 
0v1.336H8.001V8.667h5.334v5.332h-2.669v-.001zm12.001 
0h-1.33v-4h-1.336v4h-1.335v-4h-1.33v4h-2.671V8.667h8.002v5.331zM10.665 
10H12v2.667h-1.335V10z"/></svg>
\ No newline at end of file
+<svg role="img" viewBox="0 0 24 24" width="24" height="24" fill="#CC3534" 
xmlns="http://www.w3.org/2000/svg";><title>NPM icon</title><path d="M0 
7.334v8h6.666v1.332H12v-1.332h12v-8H0zm6.666 
6.664H5.334v-4H3.999v4H1.335V8.667h5.331v5.331zm4 
0v1.336H8.001V8.667h5.334v5.332h-2.669v-.001zm12.001 
0h-1.33v-4h-1.336v4h-1.335v-4h-1.33v4h-2.671V8.667h8.002v5.331zM10.665 
10H12v2.667h-1.335V10z"/></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

Reply via email to