# HG changeset patch # Parent 96b2950a91e3b8253cf8be652187acf8812502eb RT-38192: CSS support for Region as graphicProperty on Labeled diff -r 96b2950a91e3 modules/controls/src/main/java/javafx/scene/control/Labeled.java --- a/modules/controls/src/main/java/javafx/scene/control/Labeled.java Tue Aug 19 12:52:20 2014 -0400 +++ b/modules/controls/src/main/java/javafx/scene/control/Labeled.java Fri Aug 22 14:36:42 2014 -0400 @@ -34,10 +34,16 @@ import com.sun.javafx.css.converters.SizeConverter; import com.sun.javafx.css.converters.StringConverter; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.sun.javafx.css.converters.URLConverter; +import com.sun.javafx.scene.control.Logging; import javafx.beans.property.BooleanProperty; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; @@ -66,6 +72,7 @@ import javafx.css.StyleableObjectProperty; import javafx.css.StyleableProperty; import javafx.css.StyleableStringProperty; +import sun.util.logging.PlatformLogger; /** @@ -465,9 +472,9 @@ protected void invalidated() { // need to call super.get() here since get() is overridden to return the graphicProperty's value - final String url = super.get(); + final String value = super.get(); - if (url == null) { + if (value == null) { ((StyleableProperty)(WritableValue)graphicProperty()).applyStyle(origin, null); } else { // RT-34466 - if graphic's url is the same as this property's value, then don't overwrite. @@ -477,12 +484,38 @@ final Image image = imageView.getImage(); if (image != null) { final String imageViewUrl = image.impl_getUrl(); - if (url.equals(imageViewUrl)) return; + if (value.equals(imageViewUrl)) return; } } - final Image img = StyleManager.getInstance().getCachedImage(url); + if (value.startsWith("fxml:")) { + try { + URL url = URI.create(value).toURL(); + Node node = (Node)url.getContent(); + ((StyleableProperty)(WritableValue)graphicProperty()).applyStyle(origin, node); + } catch (MalformedURLException malf) { + PlatformLogger logger = Logging.getControlsLogger(); + if (logger.isLoggable(PlatformLogger.Level.WARNING)) { + logger.warning(malf.toString()); + } + } catch (ClassCastException cce) { + PlatformLogger logger = Logging.getControlsLogger(); + if (logger.isLoggable(PlatformLogger.Level.WARNING)) { + logger.warning(cce.toString()); + } + } catch (IOException ioe) { + PlatformLogger logger = Logging.getControlsLogger(); + if (logger.isLoggable(PlatformLogger.Level.WARNING)) { + logger.warning(ioe.toString()); + } + } finally { + return; + } + + } + + final Image img = StyleManager.getInstance().getCachedImage(value); if (img != null) { // diff -r 96b2950a91e3 modules/fxml/src/main/java/sun/net/www/protocol/fxml/FXMLConnection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/fxml/src/main/java/sun/net/www/protocol/fxml/FXMLConnection.java Fri Aug 22 14:36:42 2014 -0400 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, 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 sun.net.www.protocol.fxml; + +import javafx.fxml.FXMLLoader; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; + +/** + * URLConnection for fxml: URI which follows the data: URI spec http://www.ietf.org/rfc/rfc2397. + * @since JavaFX 8u40 + */ +final class FXMLConnection extends URLConnection { + + FXMLConnection(URL url) { + super(url); + } + + @Override + public void connect() throws IOException { + connected = true; + } + + @Override + public InputStream getInputStream() throws IOException { + String file = url.getFile(); + int dataIndex = Handler.indexOfData(file); + byte[] bytes = Handler.getData(file, dataIndex); + + ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); + return inputStream; + } + + @Override + public Object getContent() throws IOException { + try (InputStream inputStream = getInputStream()) { + FXMLLoader loader = new FXMLLoader(Charset.forName("UTF-8")); + Object obj = loader.load(inputStream); + return obj; + } catch (IOException ioe) { + throw ioe; + } + } + +} diff -r 96b2950a91e3 modules/fxml/src/main/java/sun/net/www/protocol/fxml/Handler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/fxml/src/main/java/sun/net/www/protocol/fxml/Handler.java Fri Aug 22 14:36:42 2014 -0400 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2014, 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 sun.net.www.protocol.fxml; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Base64; +import java.util.Locale; + +/** + * Handler for fxml: URI which follows the data: URI spec http://www.ietf.org/rfc/rfc2397. + * @since JavaFX 8u40 + */ +final public class Handler extends java.net.URLStreamHandler { + + protected java.net.URLConnection openConnection(URL u) + throws IOException { + return new FXMLConnection(u); + } + + // find in http://www.ietf.org/rfc/rfc2397 data: URI + static int indexOfData(String spec) { + + if (spec == null) return -1; + + final int length = spec.length(); + int index = spec.indexOf(','); + + // index could be -1. be forgiving if url doesn't have a comma + return index + 1; + } + + // parse http://www.ietf.org/rfc/rfc2397 data: URI to get the part + static byte[] getData(String spec, int dataIndex) { + + if (dataIndex == -1) return new byte[0]; + + String data = spec.substring(dataIndex); + String header = dataIndex > 0 ? spec.substring(0, dataIndex-1).toLowerCase(Locale.ROOT) : ""; + byte[] byteData = null; + + if (header.contains(";base64")) { + byteData = Base64.getDecoder().decode(data); + } + else { + String charset = "US-ASCII"; + int charsetOffset = header.indexOf(";charset="); + if (charsetOffset != -1) { + int beginIndex = charsetOffset + ";charset=".length(); + charset = header.substring(beginIndex).toUpperCase(Locale.ROOT); + } + try { + byteData = URLDecoder.decode(data, charset).getBytes(); + } catch (UnsupportedEncodingException uee) { + return new byte[0]; + } + } + return byteData; + } + + /** + * Compare two fxml data URLs, which are the same if the FXML is the same, regardless of encoding. + */ + @Override + protected boolean sameFile(URL u1, URL u2) { + if (!u1.getProtocol().equals("fxml") || !u2.getProtocol().equals("fxml")) + return false; + + String file1 = u1.getFile(); + String file2 = u2.getFile(); + + int dataIndex1 = indexOfData(file1); + int dataIndex2 = indexOfData(file2); + + if (dataIndex1 == -1 ? dataIndex2 != -1 : dataIndex2 == -1) { + return false; + } + + byte[] data1 = getData(file1, dataIndex1); + byte[] data2 = getData(file2, dataIndex2); + + return Arrays.equals(data1, data2); + } + + @Override + protected int hashCode(URL u) { + + int h = 7; + + String protocol = u.getProtocol(); + if (protocol != null) h += protocol.hashCode(); + + String file = u.getFile(); + byte[] data = getData(file, indexOfData(file)); + h += Arrays.hashCode(data); + + return h; + } + +} diff -r 96b2950a91e3 modules/fxml/src/test/java/sun/net/www/protocol/fxml/FXMLConnectionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/fxml/src/test/java/sun/net/www/protocol/fxml/FXMLConnectionTest.java Fri Aug 22 14:36:42 2014 -0400 @@ -0,0 +1,175 @@ +package sun.net.www.protocol.fxml; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.Base64; + +import javafx.fxml.LoadException; +import javafx.scene.layout.Region; +import org.junit.Test; +import static org.junit.Assert.*; + +public class FXMLConnectionTest { + + final private static URL UTF_8_URL; + final private static URL BASE64_URL; + final private static URL NO_DATA_URL; + final private static URL BAD_FXML_URL; + + static { + + URL utf_8_url = null; + + String FXML = ""; + + try { + utf_8_url = URI.create("fxml:,"+URLEncoder.encode(FXML, "UTF-8")).toURL(); + } catch (MalformedURLException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF_8_URL = utf_8_url; + + URL base64_url = null; + try ( + StringReader stringReader = new StringReader(FXML); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ) { + int ch = -1; + while ((ch = stringReader.read()) != -1) { + byteArrayOutputStream.write(ch); + } + String base64_encoded_data = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); + base64_url = URI.create("fxml:;base64,"+base64_encoded_data).toURL(); + + } catch (MalformedURLException malf) { + malf.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + + BASE64_URL = base64_url; + + URL no_data_url = null; + try { + no_data_url = URI.create("fxml:,").toURL(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + + NO_DATA_URL = no_data_url; + + URL bad_fxml_url = null; + try { + // bad end tag + String BAD_FXML = ""; + bad_fxml_url = URI.create("fxml:,"+URLEncoder.encode(BAD_FXML, "UTF-8")).toURL(); + } catch (MalformedURLException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + + BAD_FXML_URL = bad_fxml_url; + } + + @Test + public void testConnect() throws Exception { + + try { + URLConnection connection = UTF_8_URL.openConnection(); + assertEquals(FXMLConnection.class, connection.getClass()); + } catch (IOException ioe) { + fail(ioe.toString()); + } + + } + + @Test + public void testGetInputStream() throws Exception { + + try { + URLConnection connection = UTF_8_URL.openConnection(); + InputStream inputStream = connection.getInputStream(); + while (inputStream.read() != -1) ; + } catch (IOException ioe) { + fail(ioe.toString()); + } + + try { + URLConnection connection = BASE64_URL.openConnection(); + InputStream inputStream = connection.getInputStream(); + while (inputStream.read() != -1) ; + } catch (IOException ioe) { + fail(ioe.toString()); + } + + // Even though the FXML is bad, we should still be able to read the stream + try { + URLConnection connection = NO_DATA_URL.openConnection(); + InputStream inputStream = connection.getInputStream(); + while (inputStream.read() != -1) ; + } catch (IOException ioe) { + fail(ioe.toString()); + } + + // Even though the FXML is bad, we should still be able to read the stream + try { + URLConnection connection = BAD_FXML_URL.openConnection(); + InputStream inputStream = connection.getInputStream(); + while (inputStream.read() != -1) ; + } catch (IOException ioe) { + fail(ioe.toString()); + } + + + } + + @Test + public void testGetContent() throws Exception { + + try { + URLConnection connection = UTF_8_URL.openConnection(); + Region region = (Region)connection.getContent(); + assertTrue(region.getStyleClass().contains("graphic")); + } catch (ClassCastException cce) { + fail(cce.toString()); + } catch (IOException ioe) { + fail(ioe.toString()); + } + + try { + URLConnection connection = BASE64_URL.openConnection(); + Region region = (Region)connection.getContent(); + assertTrue(region.getStyleClass().contains("graphic")); + } catch (IOException ioe) { + fail(ioe.toString()); + } + + try { + URLConnection connection = NO_DATA_URL.openConnection(); + Region region = (Region)connection.getContent(); + fail("should never get here!"); + } catch (LoadException expected) { + // passed the test! + } catch (IOException ioe) { + fail("expected LoadException, got " + ioe.toString()); + } + + try { + URLConnection connection = BAD_FXML_URL.openConnection(); + Region region = (Region) connection.getContent(); + fail("should never get here!"); + } catch (LoadException expected) { + // passed the test! + } catch (IOException ioe) { + fail("expected LoadException, got " + ioe.toString()); + } + } +} \ No newline at end of file diff -r 96b2950a91e3 modules/fxml/src/test/java/sun/net/www/protocol/fxml/HandlerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/fxml/src/test/java/sun/net/www/protocol/fxml/HandlerTest.java Fri Aug 22 14:36:42 2014 -0400 @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2014, 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 sun.net.www.protocol.fxml; + +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLEncoder; +import java.util.Base64; + +import static org.junit.Assert.*; + +public class HandlerTest { + + final private static String UTF_8_ENCODED_DATA; + final private static String ISO_8859_1_ENCODED_DATA; + final private static String BASE64_ENCODED_DATA; + final private static String FXML; + final private static byte[] FXML_BYTES; + + static { + + String utf_8_encoded_data = null; + String iso_8859_1_encoded_data = null; + byte[] fxml_bytes = null; + + FXML = ""; + + try { + utf_8_encoded_data = URLEncoder.encode(FXML, "UTF-8"); + iso_8859_1_encoded_data = URLEncoder.encode(FXML, "ISO-8859-1"); + fxml_bytes = FXML.getBytes("US-ASCII"); + } catch (UnsupportedEncodingException uee) { + uee.printStackTrace(); + } + + UTF_8_ENCODED_DATA = utf_8_encoded_data; + ISO_8859_1_ENCODED_DATA = iso_8859_1_encoded_data; + FXML_BYTES = fxml_bytes; + + String base64_encoded_data = null; + try ( + StringReader stringReader = new StringReader(FXML); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ) { + int ch = -1; + while ((ch = stringReader.read()) != -1) { + byteArrayOutputStream.write(ch); + } + base64_encoded_data = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); + + } catch (IOException ioe) { + ioe.printStackTrace(); + } + + BASE64_ENCODED_DATA = base64_encoded_data; + + } + + @Test + public void testIndexOfData() throws Exception { + + String spec = "," + UTF_8_ENCODED_DATA; + int expected = ",".length(); + int observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = "" + UTF_8_ENCODED_DATA; + expected = "".length(); + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = ";base64," + BASE64_ENCODED_DATA; + expected = ";base64,".length(); + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = "text/xml;base64," + BASE64_ENCODED_DATA; + expected = "text/xml;base64,".length(); + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = ";charset=ISO-8859-1," + ISO_8859_1_ENCODED_DATA; + expected = ";charset=ISO-8859-1,".length(); + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = "text/xml;charset=ISO-8859-1," + ISO_8859_1_ENCODED_DATA; + expected = "text/xml;charset=ISO-8859-1,".length(); + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + // + // missing data tests + // + spec = ""; + expected = 0; + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = null; + expected = -1; + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + spec = "text/xml;charset=ISO-8859-1,"; + expected = "text/xml;charset=ISO-8859-1,".length(); + observed = Handler.indexOfData(spec); + assertEquals(expected, observed); + + } + + @Test + public void testGetData() throws Exception { + + String spec = "," + UTF_8_ENCODED_DATA; + byte[] observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + spec = ";base64," + BASE64_ENCODED_DATA; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + spec = "text/xml;base64," + BASE64_ENCODED_DATA; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + spec = ";charset=ISO-8859-1," + ISO_8859_1_ENCODED_DATA; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + spec = "text/xml;charset=ISO-8859-1," + ISO_8859_1_ENCODED_DATA; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + spec = "text/xml;charset=ISO-8859-1;base64," + BASE64_ENCODED_DATA; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + spec = "text/xml;base64;charset=ISO-8859-1," + BASE64_ENCODED_DATA; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(FXML_BYTES, observed); + + // + // missing data tests + // + byte[] expected = new byte[0]; + spec = ""; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(expected, observed); + + spec = null; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(expected, observed); + + spec = ","; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(expected, observed); + + spec = ";base64,"; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(expected, observed); + + spec = ";charset=ISO-8859-1,"; + observed = Handler.getData(spec, Handler.indexOfData(spec)); + assertArrayEquals(expected, observed); + } + + @Test + public void testSameFile() throws Exception { + Handler handler = new Handler(); + + try { + String spec1 = "fxml:," + UTF_8_ENCODED_DATA; + String spec2 = "fxml:," + UTF_8_ENCODED_DATA; + URL url1 = URI.create(spec1).toURL(); + URL url2 = URI.create(spec2).toURL(); + assertTrue(handler.sameFile(url1, url2)); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + + try { + String spec1 = "fxml:," + UTF_8_ENCODED_DATA; + String spec2 = "fxml:;base64," + BASE64_ENCODED_DATA; + URL url1 = URI.create(spec1).toURL(); + URL url2 = URI.create(spec2).toURL(); + assertTrue(handler.sameFile(url1, url2)); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + + try { + String spec1 = "fxml:," + UTF_8_ENCODED_DATA; + String spec2 = "fxml:;charset=ISO-8859-1," + ISO_8859_1_ENCODED_DATA; + URL url1 = URI.create(spec1).toURL(); + URL url2 = URI.create(spec2).toURL(); + assertTrue(handler.sameFile(url1, url2)); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + + try { + String spec1 = "fxml:," + UTF_8_ENCODED_DATA; + // Here, fxml data is different length + String spec2 = "fxml:," + URLEncoder.encode("", "US-ASCII"); + URL url1 = URI.create(spec1).toURL(); + URL url2 = URI.create(spec2).toURL(); + assertFalse(handler.sameFile(url1, url2)); + } catch (UnsupportedEncodingException uee) { + fail(uee.toString()); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + + try { + String spec1 = "fxml:," + UTF_8_ENCODED_DATA; + // here, fxml data is same length, but different value + String spec2 = "fxml:," + URLEncoder.encode("", "US-ASCII"); + URL url1 = URI.create(spec1).toURL(); + URL url2 = URI.create(spec2).toURL(); + assertFalse(handler.sameFile(url1, url2)); + } catch (UnsupportedEncodingException uee) { + fail(uee.toString()); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + } + + @Test + public void testHashCode() throws Exception { + Handler handler = new Handler(); + + try { + String spec = "fxml:," + UTF_8_ENCODED_DATA; + URL url = URI.create(spec).toURL(); + int hashCode = handler.hashCode(url); + assertTrue(hashCode > 0); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + + try { + String spec = "fxml:,"; + URL url = URI.create(spec).toURL(); + int hashCode = handler.hashCode(url); + assertTrue(hashCode > 0); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + + try { + String spec = "fxml:;charset=ISO-8859-1," + ISO_8859_1_ENCODED_DATA; + URL url = URI.create(spec).toURL(); + int hashCode = handler.hashCode(url); + assertTrue(hashCode > 0); + } catch (MalformedURLException malf) { + fail(malf.toString()); + } + } +} \ No newline at end of file diff -r 96b2950a91e3 modules/graphics/src/main/java/com/sun/javafx/css/converters/URLConverter.java --- a/modules/graphics/src/main/java/com/sun/javafx/css/converters/URLConverter.java Tue Aug 19 12:52:20 2014 -0400 +++ b/modules/graphics/src/main/java/com/sun/javafx/css/converters/URLConverter.java Fri Aug 22 14:36:42 2014 -0400 @@ -31,10 +31,15 @@ import javafx.scene.text.Font; import sun.util.logging.PlatformLogger; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Base64; +import java.util.Locale; /** * Convert url("") a URL string resolved relative to the location of the stylesheet. @@ -84,7 +89,8 @@ // package for testing URL resolve(String stylesheetUrl, String resource) { - if (resource == null || resource.trim().isEmpty()) return null; + String spec = null; + if (resource == null || (spec = resource.trim()).isEmpty()) return null; try { @@ -92,7 +98,8 @@ // 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(resource.trim()); + boolean isFxml = "fxml:".regionMatches(true, 0, spec, 0, "fxml:".length()); + URI resourceUri = isFxml ? fxmlURI(spec) : new URI(spec); if (resourceUri.isAbsolute()) { return resourceUri.toURL(); @@ -143,7 +150,28 @@ } + // Assumes spec is trimmed + static URI fxmlURI(String spec) throws URISyntaxException, MalformedURLException { + int dataIndex = spec.indexOf(',') + 1; + String data = spec.substring(dataIndex); + String header = dataIndex > 0 ? spec.substring(0, dataIndex-1).toLowerCase() : ""; + + // If the header contains ;base64 or ;charset=, then assume the data is encoded. + // Otherwise, assume the data is not encoded but is in human-readable form that needs to be encoded + if (!header.contains(";base64") && !header.contains(";charset=")) { + try { + data = URLEncoder.encode(data, "UTF-8"); + } catch (UnsupportedEncodingException uee) { + // Fall through - new URI will throw an exception on our behalf + // (but if US-ASCII isn't a supported encoding then something is awfully wrong with the JDK!) + } + } + + String newSpec = spec.substring(0,dataIndex).concat(data); + URI uri = new URI(newSpec); + return uri; + } @Override public String toString() { diff -r 96b2950a91e3 modules/graphics/src/test/java/com/sun/javafx/css/converters/URLConverterTest.java --- a/modules/graphics/src/test/java/com/sun/javafx/css/converters/URLConverterTest.java Tue Aug 19 12:52:20 2014 -0400 +++ b/modules/graphics/src/test/java/com/sun/javafx/css/converters/URLConverterTest.java Fri Aug 22 14:36:42 2014 -0400 @@ -25,9 +25,16 @@ package com.sun.javafx.css.converters; +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.net.URI; import java.net.URL; +import java.net.URLEncoder; +import java.util.Base64; + import javafx.css.ParsedValue; import javafx.css.StyleConverter; +import javafx.scene.Node; import javafx.scene.text.Font; import com.sun.javafx.css.ParsedValueImpl; import org.junit.Test; @@ -118,5 +125,43 @@ String result = value.convert(font); assertEquals(expResult, result); } - + + @Test + public void testCreateFXMLUri() { + + try { + String uriString = "fxml:,"; + String expected = "fxml:," + URLEncoder.encode("", "UTF-8"); + URI uri = URLConverter.fxmlURI(uriString); + assertEquals(expected, uri.toString()); + } catch (Exception e) { + fail(e.toString()); + } + + try { + String uriString = "fxml:;charset=ISO-8859-1," + URLEncoder.encode("", "ISO-8859-1"); + URI uri = URLConverter.fxmlURI(uriString); + assertEquals(uriString, uri.toString()); + } catch (Exception e) { + fail(e.toString()); + } + + try { + StringReader stringReader = new StringReader(""); + + // encoding to base64 would be done in URLConverter if not already base64 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + int ch = -1; + while ((ch = stringReader.read()) != -1) { + byteArrayOutputStream.write(ch); + } + String s = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); + String uriString = "fxml:;base64," + s; + URI uri = URLConverter.fxmlURI(uriString); + assertEquals(uriString, uri.toString()); + } catch (Exception e) { + fail(e.toString()); + } + + } }