--- old/modules/graphics/src/main/java/com/sun/javafx/css/converters/URLConverter.java 2015-09-03 15:35:11.357757300 -0700 +++ /dev/null 2015-09-03 15:35:12.000000000 -0700 @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.javafx.css.converters; - -import com.sun.javafx.css.StyleConverterImpl; -import javafx.application.Application; -import javafx.css.ParsedValue; -import javafx.css.StyleConverter; -import javafx.scene.text.Font; -import sun.util.logging.PlatformLogger; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.security.AccessController; -import java.security.CodeSource; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.security.ProtectionDomain; - -/** - * Convert url("") a URL string resolved relative to the location of the stylesheet. - */ -public final class URLConverter extends StyleConverterImpl { - - // lazy, thread-safe instatiation - private static class Holder { - static final URLConverter INSTANCE = new URLConverter(); - static final SequenceConverter SEQUENCE_INSTANCE = new SequenceConverter(); - } - - public static StyleConverter getInstance() { - return Holder.INSTANCE; - } - - private URLConverter() { - super(); - } - - @Override - public String convert(ParsedValue value, Font font) { - - String url = null; - - ParsedValue[] values = value.getValue(); - - String resource = values.length > 0 ? StringConverter.getInstance().convert(values[0], font) : null; - - if (resource != null && resource.trim().isEmpty() == false) { - - if (resource.startsWith("url(")) { - resource = com.sun.javafx.util.Utils.stripQuotes(resource.substring(4, resource.length() - 1)); - } else { - resource = com.sun.javafx.util.Utils.stripQuotes(resource); - } - - String stylesheetURL = values.length > 1 && values[1] != null ? (String)values[1].getValue() : null; - URL resolvedURL = resolve(stylesheetURL, resource); - - if (resolvedURL != null) url = resolvedURL.toExternalForm(); - } - - return url; - } - - // package for testing - URL resolve(String stylesheetUrl, String resource) { - - - final String resourcePath = (resource != null) ? resource.trim() : null; - if (resourcePath == null || resourcePath.isEmpty()) return null; - - try { - - // Note: the same code (pretty much) also appears in StyleManager - - // if stylesheetUri is null, then we're dealing with an in-line style. - // If there is no scheme part, then the url is interpreted as being relative to the application's class-loader. - URI resourceUri = new URI(resourcePath); - - if (resourceUri.isAbsolute()) { - return resourceUri.toURL(); - } - - URL rtJarUrl = resolveRuntimeImport(resourceUri); - if (rtJarUrl != null) { - return rtJarUrl; - } - - final String path = resourceUri.getPath(); - if (path.startsWith("/")) { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - return contextClassLoader.getResource(path.substring(1)); - } - - final String stylesheetPath = (stylesheetUrl != null) ? stylesheetUrl.trim() : null; - - if (stylesheetPath != null && stylesheetPath.isEmpty() == false) { - - URI stylesheetUri = new URI(stylesheetPath); - - if (stylesheetUri.isOpaque() == false) { - - URI resolved = stylesheetUri.resolve(resourceUri); - return resolved.toURL(); - - } else { - - // stylesheet URI is something like jar:file: - URL url = stylesheetUri.toURL(); - return new URL(url, resourceUri.getPath()); - } - } - - - // URL doesn't have scheme or stylesheetUrl is null - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - return contextClassLoader.getResource(path); - - - } catch (final MalformedURLException|URISyntaxException e) { - PlatformLogger cssLogger = com.sun.javafx.util.Logging.getCSSLogger(); - if (cssLogger.isLoggable(PlatformLogger.Level.WARNING)) { - cssLogger.warning(e.getLocalizedMessage()); - } - - return null; - } - - } - - - // - // Resolve a path from an @import that implies jfxrt.jar, - // e.g., @import "com/sun/javafx/scene/control/skin/modena/modena.css". - // - // See also StyleSheet#loadStylesheet(String) - // - private URL resolveRuntimeImport(final URI resourceUri) { - - - final String path = resourceUri.getPath(); - final String resourcePath = path.startsWith("/") ? path.substring(1) : path; - - if ((resourcePath.startsWith("com/sun/javafx/scene/control/skin/modena/") || - resourcePath.startsWith("com/sun/javafx/scene/control/skin/caspian/")) && - (resourcePath.endsWith(".css") || resourcePath.endsWith(".bss"))) { - - final SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - // If the SecurityManager is not null, then just look up the resource on the class-path. - // If there is a SecurityManager, the URLClassPath getResource call will return null, - // so fall through and create a URL from the code-source URI - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - final URL resolved = contextClassLoader.getResource(resourcePath); - return resolved; - } - - // check whether the path is file from our runtime jar - try { - final URL rtJarURL = AccessController.doPrivileged((PrivilegedExceptionAction) () -> { - // getProtectionDomain either throws a SecurityException or returns a non-null value - final ProtectionDomain protectionDomain = Application.class.getProtectionDomain(); - // If we're running with a SecurityManager, then the ProtectionDomain will have a CodeSource - final CodeSource codeSource = protectionDomain.getCodeSource(); - // The CodeSource location will be our runtime jar - return codeSource.getLocation(); - }); - - final URI rtJarURI = rtJarURL.toURI(); - - String scheme = rtJarURI.getScheme(); - String rtJarPath = rtJarURI.getPath(); - - // - // Just because we're running with a SecurityManager doesn't mean the jfxrt jar path is - // a jar: URL. But the code in StyleManager wants it to be. So if we have - // file:/blah/rt/lib/ext/jfxrt.jar make it jar:file:/blah/rt/lib/ext/jfxrt.jar!/ - // - // If the path doesn't end with .jar, then we are just dealing with a normal file: path - // - if ("file".equals(scheme) && rtJarPath.endsWith(".jar")) { - if ("file".equals(scheme)) { - scheme = "jar:file"; - rtJarPath = rtJarPath.concat("!/"); - } - } - rtJarPath = rtJarPath.concat(resourcePath); - - final String rtJarUserInfo = rtJarURI.getUserInfo(); - final String rtJarHost = rtJarURI.getHost(); - final int rtJarPort = rtJarURI.getPort(); - - // - // Put together a new URI from the pieces of rtJarURI. We cannot use resolve here since - // the scheme and path may have been munged. - // - URI resolved = new URI(scheme, rtJarUserInfo, rtJarHost, rtJarPort, rtJarPath, null, null); - return resolved.toURL(); - - } catch (URISyntaxException | MalformedURLException | PrivilegedActionException ignored) { - // Allow this method to return null so the caller will try to further resolve the path. - // If nothing else, an error message will result when the converted URL is consumed. - } - } - return null; - } - - @Override - public String toString() { - return "URLType"; - } - - public static final class SequenceConverter extends StyleConverterImpl[], String[]> { - - public static SequenceConverter getInstance() { - return Holder.SEQUENCE_INSTANCE; - } - - private SequenceConverter() { - super(); - } - - @Override - public String[] convert(ParsedValue[], String[]> value, Font font) { - ParsedValue[] layers = value.getValue(); - String[] urls = new String[layers.length]; - for (int layer = 0; layer < layers.length; layer++) { - urls[layer] = URLConverter.getInstance().convert(layers[layer], font); - } - return urls; - } - - @Override - public String toString() { - return "URLSeqType"; - } - } - -} --- /dev/null 2015-09-03 15:35:12.000000000 -0700 +++ new/modules/graphics/src/main/java/javafx/css/converter/URLConverter.java 2015-09-03 15:35:10.531710100 -0700 @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.css.converter; + +import javafx.application.Application; +import javafx.css.ParsedValue; +import javafx.css.StyleConverter; +import javafx.scene.text.Font; +import sun.util.logging.PlatformLogger; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; + +/** + * Convert url("") a URL string resolved relative to the location of the stylesheet. + * + * @since 9 + */ +public final class URLConverter extends StyleConverter { + + // lazy, thread-safe instatiation + private static class Holder { + static final URLConverter INSTANCE = new URLConverter(); + static final SequenceConverter SEQUENCE_INSTANCE = new SequenceConverter(); + } + + public static StyleConverter getInstance() { + return Holder.INSTANCE; + } + + private URLConverter() { + super(); + } + + @Override + public String convert(ParsedValue value, Font font) { + + String url = null; + + ParsedValue[] values = value.getValue(); + + String resource = values.length > 0 ? StringConverter.getInstance().convert(values[0], font) : null; + + if (resource != null && resource.trim().isEmpty() == false) { + + if (resource.startsWith("url(")) { + resource = com.sun.javafx.util.Utils.stripQuotes(resource.substring(4, resource.length() - 1)); + } else { + resource = com.sun.javafx.util.Utils.stripQuotes(resource); + } + + String stylesheetURL = values.length > 1 && values[1] != null ? (String)values[1].getValue() : null; + URL resolvedURL = resolve(stylesheetURL, resource); + + if (resolvedURL != null) url = resolvedURL.toExternalForm(); + } + + return url; + } + + // package for testing + URL resolve(String stylesheetUrl, String resource) { + + + final String resourcePath = (resource != null) ? resource.trim() : null; + if (resourcePath == null || resourcePath.isEmpty()) return null; + + try { + + // Note: the same code (pretty much) also appears in StyleManager + + // if stylesheetUri is null, then we're dealing with an in-line style. + // If there is no scheme part, then the url is interpreted as being relative to the application's class-loader. + URI resourceUri = new URI(resourcePath); + + if (resourceUri.isAbsolute()) { + return resourceUri.toURL(); + } + + URL rtJarUrl = resolveRuntimeImport(resourceUri); + if (rtJarUrl != null) { + return rtJarUrl; + } + + final String path = resourceUri.getPath(); + if (path.startsWith("/")) { + final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + return contextClassLoader.getResource(path.substring(1)); + } + + final String stylesheetPath = (stylesheetUrl != null) ? stylesheetUrl.trim() : null; + + if (stylesheetPath != null && stylesheetPath.isEmpty() == false) { + + URI stylesheetUri = new URI(stylesheetPath); + + if (stylesheetUri.isOpaque() == false) { + + URI resolved = stylesheetUri.resolve(resourceUri); + return resolved.toURL(); + + } else { + + // stylesheet URI is something like jar:file: + URL url = stylesheetUri.toURL(); + return new URL(url, resourceUri.getPath()); + } + } + + + // URL doesn't have scheme or stylesheetUrl is null + final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + return contextClassLoader.getResource(path); + + + } catch (final MalformedURLException|URISyntaxException e) { + PlatformLogger cssLogger = com.sun.javafx.util.Logging.getCSSLogger(); + if (cssLogger.isLoggable(PlatformLogger.Level.WARNING)) { + cssLogger.warning(e.getLocalizedMessage()); + } + + return null; + } + + } + + + // + // Resolve a path from an @import that implies jfxrt.jar, + // e.g., @import "com/sun/javafx/scene/control/skin/modena/modena.css". + // + // See also StyleSheet#loadStylesheet(String) + // + private URL resolveRuntimeImport(final URI resourceUri) { + + + final String path = resourceUri.getPath(); + final String resourcePath = path.startsWith("/") ? path.substring(1) : path; + + if ((resourcePath.startsWith("com/sun/javafx/scene/control/skin/modena/") || + resourcePath.startsWith("com/sun/javafx/scene/control/skin/caspian/")) && + (resourcePath.endsWith(".css") || resourcePath.endsWith(".bss"))) { + + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + // If the SecurityManager is not null, then just look up the resource on the class-path. + // If there is a SecurityManager, the URLClassPath getResource call will return null, + // so fall through and create a URL from the code-source URI + final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + final URL resolved = contextClassLoader.getResource(resourcePath); + return resolved; + } + + // check whether the path is file from our runtime jar + try { + final URL rtJarURL = AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + // getProtectionDomain either throws a SecurityException or returns a non-null value + final ProtectionDomain protectionDomain = Application.class.getProtectionDomain(); + // If we're running with a SecurityManager, then the ProtectionDomain will have a CodeSource + final CodeSource codeSource = protectionDomain.getCodeSource(); + // The CodeSource location will be our runtime jar + return codeSource.getLocation(); + }); + + final URI rtJarURI = rtJarURL.toURI(); + + String scheme = rtJarURI.getScheme(); + String rtJarPath = rtJarURI.getPath(); + + // + // Just because we're running with a SecurityManager doesn't mean the jfxrt jar path is + // a jar: URL. But the code in StyleManager wants it to be. So if we have + // file:/blah/rt/lib/ext/jfxrt.jar make it jar:file:/blah/rt/lib/ext/jfxrt.jar!/ + // + // If the path doesn't end with .jar, then we are just dealing with a normal file: path + // + if ("file".equals(scheme) && rtJarPath.endsWith(".jar")) { + if ("file".equals(scheme)) { + scheme = "jar:file"; + rtJarPath = rtJarPath.concat("!/"); + } + } + rtJarPath = rtJarPath.concat(resourcePath); + + final String rtJarUserInfo = rtJarURI.getUserInfo(); + final String rtJarHost = rtJarURI.getHost(); + final int rtJarPort = rtJarURI.getPort(); + + // + // Put together a new URI from the pieces of rtJarURI. We cannot use resolve here since + // the scheme and path may have been munged. + // + URI resolved = new URI(scheme, rtJarUserInfo, rtJarHost, rtJarPort, rtJarPath, null, null); + return resolved.toURL(); + + } catch (URISyntaxException | MalformedURLException | PrivilegedActionException ignored) { + // Allow this method to return null so the caller will try to further resolve the path. + // If nothing else, an error message will result when the converted URL is consumed. + } + } + return null; + } + + @Override + public String toString() { + return "URLType"; + } + + public static final class SequenceConverter extends StyleConverter[], String[]> { + + public static SequenceConverter getInstance() { + return Holder.SEQUENCE_INSTANCE; + } + + private SequenceConverter() { + super(); + } + + @Override + public String[] convert(ParsedValue[], String[]> value, Font font) { + ParsedValue[] layers = value.getValue(); + String[] urls = new String[layers.length]; + for (int layer = 0; layer < layers.length; layer++) { + urls[layer] = URLConverter.getInstance().convert(layers[layer], font); + } + return urls; + } + + @Override + public String toString() { + return "URLSeqType"; + } + } + +}