changeset 9092:ccc3bab2e6e5 9-b68

Automated merge with http://hg.openjdk.java.net/openjfx/9/rt
author kcr
date Fri, 05 Jun 2015 17:39:54 -0700
parents 04d10763a55e ec99b7b4879a
children 66b001fe928a d19f81227224
files
diffstat 41 files changed, 1670 insertions(+), 1164 deletions(-) [+]
line wrap: on
line diff
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/language/stringbinding/StringBindingApp.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/language/stringbinding/StringBindingApp.java	Fri Jun 05 17:39:54 2015 -0700
@@ -60,7 +60,8 @@
 public class StringBindingApp extends Application {
 
     public Parent createContent() {
-        final SimpleDateFormat format = new SimpleDateFormat("mm/dd/yyyy");
+        final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
+        format.setLenient(false);
         final TextField dateField = new TextField();
         dateField.setPromptText("Enter a birth date");
         dateField.setMaxHeight(TextField.USE_PREF_SIZE);
@@ -83,15 +84,18 @@
                     Date today = new Date();
                     Calendar c2 = Calendar.getInstance();
                     c2.setTime(today);
-
+                    
                     if (c.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR) - 1
                             && c.get(Calendar.YEAR) == c2.get(Calendar.YEAR)) {
                         return "You were born yesterday";
+                    } else if (c.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR)
+                               && c.get(Calendar.YEAR) == c2.get(Calendar.YEAR)) {
+                        return "You were born today";
                     } else {
                         return "You were born " + format.format(date);
                     }
                 } catch (Exception e) {
-                    return "Enter a valid birth date (mm/dd/yyyy)";
+                    return "Enter your valid birth date (mm/dd/yyyy)";
                 }
             }
         });
--- a/modules/controls/src/main/java/javafx/scene/chart/AreaChart.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/main/java/javafx/scene/chart/AreaChart.java	Fri Jun 05 17:39:54 2015 -0700
@@ -297,7 +297,7 @@
                     int last = dataListSize - 1;
                     item.setXValue(series.getData().get(last).getXValue());
                     item.setYValue(series.getData().get(last).getYValue());
-                } else {
+                } else if (symbol != null) {
                     // fade out symbol
                     symbol.setOpacity(0);
                     FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
--- a/modules/controls/src/main/java/javafx/scene/chart/LineChart.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/main/java/javafx/scene/chart/LineChart.java	Fri Jun 05 17:39:54 2015 -0700
@@ -304,59 +304,56 @@
         if (shouldAnimate()) {
             XYValueMap.clear();
             boolean animate = false;
-            if (itemIndex > 0 && itemIndex < series.getDataSize()) {
+            // dataSize represents size of currently visible data. After this operation, the number will decrement by 1
+            final int dataSize = series.getDataSize();
+            // This is the size of current data list in Series. Note that it might be totaly different from dataSize as
+            // some big operation might have happened on the list.
+            final int dataListSize = series.getData().size();
+            if (itemIndex > 0 && itemIndex < dataSize - 1) {
                 animate = true;
                 Data<X,Y> p1 = series.getItem(itemIndex - 1);
                 Data<X,Y> p2 = series.getItem(itemIndex + 1);
-                if (p1 != null && p2 != null) {
-                    double x1 = getXAxis().toNumericValue(p1.getXValue());
-                    double y1 = getYAxis().toNumericValue(p1.getYValue());
-                    double x3 = getXAxis().toNumericValue(p2.getXValue());
-                    double y3 = getYAxis().toNumericValue(p2.getYValue());
+                double x1 = getXAxis().toNumericValue(p1.getXValue());
+                double y1 = getYAxis().toNumericValue(p1.getYValue());
+                double x3 = getXAxis().toNumericValue(p2.getXValue());
+                double y3 = getYAxis().toNumericValue(p2.getYValue());
 
-                    double x2 = getXAxis().toNumericValue(item.getXValue());
-                    double y2 = getYAxis().toNumericValue(item.getYValue());
-                    if (x2 > x1 && x2 < x3) {
-    //                //1.  y intercept of the line : y = ((y3-y1)/(x3-x1)) * x2 + (x3y1 - y3x1)/(x3 -x1)
-                        double y = ((y3-y1)/(x3-x1)) * x2 + (x3*y1 - y3*x1)/(x3-x1);
-                        item.setCurrentX(getXAxis().toRealValue(x2));
-                        item.setCurrentY(getYAxis().toRealValue(y2));
-                        item.setXValue(getXAxis().toRealValue(x2));
-                        item.setYValue(getYAxis().toRealValue(y));
-                    } else {
-                    //2.  we can simply use the midpoint on the line as well..
-                        double x = (x3 + x1)/2;
-                        double y = (y3 + y1)/2;
-                        item.setCurrentX(getXAxis().toRealValue(x));
-                        item.setCurrentY(getYAxis().toRealValue(y));
-                    }
+                double x2 = getXAxis().toNumericValue(item.getXValue());
+                double y2 = getYAxis().toNumericValue(item.getYValue());
+                if (x2 > x1 && x2 < x3) {
+//                //1.  y intercept of the line : y = ((y3-y1)/(x3-x1)) * x2 + (x3y1 - y3x1)/(x3 -x1)
+                    double y = ((y3-y1)/(x3-x1)) * x2 + (x3*y1 - y3*x1)/(x3-x1);
+                    item.setCurrentX(getXAxis().toRealValue(x2));
+                    item.setCurrentY(getYAxis().toRealValue(y2));
+                    item.setXValue(getXAxis().toRealValue(x2));
+                    item.setYValue(getYAxis().toRealValue(y));
+                } else {
+                //2.  we can simply use the midpoint on the line as well..
+                    double x = (x3 + x1)/2;
+                    double y = (y3 + y1)/2;
+                    item.setCurrentX(getXAxis().toRealValue(x));
+                    item.setCurrentY(getYAxis().toRealValue(y));
                 }
-            } else if (itemIndex == 0 && series.getDataSize() > 1) {
+            } else if (itemIndex == 0 && dataListSize > 1) {
                 animate = true;
-                Iterator<Data<X,Y>> iter = getDisplayedDataIterator(series);
-                if (iter.hasNext()) { // get first data value
-                    Data<X,Y> d = iter.next();
-                    item.setXValue(d.getXValue());
-                    item.setYValue(d.getYValue());
-                }
-            } else if (itemIndex == (series.getDataSize() - 1) && series.getDataSize() > 1) {
+                item.setXValue(series.getData().get(0).getXValue());
+                item.setYValue(series.getData().get(0).getYValue());
+            } else if (itemIndex == (dataSize - 1) && dataListSize > 1) {
                 animate = true;
-                int last = series.getData().size() - 1;
+                int last = dataListSize - 1;
                 item.setXValue(series.getData().get(last).getXValue());
                 item.setYValue(series.getData().get(last).getYValue());
-            } else {
+            } else if (symbol != null) {
                 // fade out symbol
-                if (symbol != null) {
-                    fadeSymbolTransition = new FadeTransition(Duration.millis(500),symbol);
-                    fadeSymbolTransition.setToValue(0);
-                    fadeSymbolTransition.setOnFinished(actionEvent -> {
-                        item.setSeries(null);
-                        getPlotChildren().remove(symbol);
-                        removeDataItemFromDisplay(series, item);
-                        symbol.setOpacity(1.0);
-                    });
-                    fadeSymbolTransition.play();
-                }
+                fadeSymbolTransition = new FadeTransition(Duration.millis(500),symbol);
+                fadeSymbolTransition.setToValue(0);
+                fadeSymbolTransition.setOnFinished(actionEvent -> {
+                    item.setSeries(null);
+                    getPlotChildren().remove(symbol);
+                    removeDataItemFromDisplay(series, item);
+                    symbol.setOpacity(1.0);
+                });
+                fadeSymbolTransition.play();
             }
             if (animate) {
                 dataRemoveTimeline = createDataRemoveTimeline(item, symbol, series);
--- a/modules/controls/src/main/java/javafx/scene/chart/StackedAreaChart.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/main/java/javafx/scene/chart/StackedAreaChart.java	Fri Jun 05 17:39:54 2015 -0700
@@ -244,17 +244,15 @@
         int itemIndex = series.getItemIndex(item);
         if (shouldAnimate()) {
             boolean animate = false;
-            if (itemIndex > 0 && itemIndex < series.getDataSize()) {
+            // dataSize represents size of currently visible data. After this operation, the number will decrement by 1
+            final int dataSize = series.getDataSize();
+            // This is the size of current data list in Series. Note that it might be totaly different from dataSize as
+            // some big operation might have happened on the list.
+            final int dataListSize = series.getData().size();
+            if (itemIndex > 0 && itemIndex < dataSize - 1) {
                 animate = true;
-                int index=0;
-
                 Data<X,Y> p1 = series.getItem(itemIndex - 1);
                 Data<X,Y> p2 = series.getItem(itemIndex + 1);
-
-                if (p2 == null) {
-                    return;
-                }
-
                 double x1 = getXAxis().toNumericValue(p1.getXValue());
                 double y1 = getYAxis().toNumericValue(p1.getYValue());
                 double x3 = getXAxis().toNumericValue(p2.getXValue());
@@ -274,16 +272,16 @@
 //                double y = (y3 + y1)/2;
 //                item.setCurrentX(x);
 //                item.setCurrentY(y);
-            } else if (itemIndex == 0 && series.getDataSize() > 1) {
+            } else if (itemIndex == 0 && dataListSize > 1) {
                 animate = true;
                 item.setXValue(series.getData().get(0).getXValue());
                 item.setYValue(series.getData().get(0).getYValue());
-            } else if (itemIndex == (series.getDataSize() - 1) && series.getDataSize() > 1) {
+            } else if (itemIndex == (dataSize - 1) && dataListSize > 1) {
                 animate = true;
-                int last = series.getData().size() - 1;
+                int last = dataListSize - 1;
                 item.setXValue(series.getData().get(last).getXValue());
                 item.setYValue(series.getData().get(last).getYValue());
-            } else {
+            } else if (symbol != null) {
                 // fade out symbol
                 symbol.setOpacity(0);
                 FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
--- a/modules/controls/src/main/java/javafx/scene/control/Dialog.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/Dialog.java	Fri Jun 05 17:39:54 2015 -0700
@@ -49,6 +49,7 @@
 import javafx.util.Callback;
 
 import com.sun.javafx.event.EventHandlerManager;
+import com.sun.javafx.tk.Toolkit;
 
 /**
  * A Dialog in JavaFX wraps a {@link DialogPane} and provides the necessary API
@@ -286,8 +287,12 @@
      * this brings up a non-blocking dialog). Users of this API must either
      * poll the {@link #resultProperty() result property}, or else add a listener
      * to the result property to be informed of when it is set.
+     * @throws IllegalStateException if this method is called on a thread
+     *     other than the JavaFX Application Thread.
      */
     public final void show() {
+        Toolkit.getToolkit().checkFxUserThread();
+
         Event.fireEvent(this, new DialogEvent(this, DialogEvent.DIALOG_SHOWING));
         if( getWidth() == Double.NaN && getHeight() == Double.NaN ) {
             dialog.sizeToScene();
@@ -301,11 +306,28 @@
     /**
      * Shows the dialog and waits for the user response (in other words, brings 
      * up a blocking dialog, with the returned value the users input).
-     * 
+     * <p>
+     * This method must be called on the JavaFX Application thread.
+     * Additionally, it must either be called from an input event handler or
+     * from the run method of a Runnable passed to
+     * {@link javafx.application.Platform#runLater Platform.runLater}.
+     * It must not be called during animation or layout processing.
+     * </p>
+     *
      * @return An {@link Optional} that contains the {@link #resultProperty() result}.
      *         Refer to the {@link Dialog} class documentation for more detail.
+     * @throws IllegalStateException if this method is called on a thread
+     *     other than the JavaFX Application Thread.
+     * @throws IllegalStateException if this method is called during
+     *     animation or layout processing.
      */
     public final Optional<R> showAndWait() {
+        Toolkit.getToolkit().checkFxUserThread();
+
+        if (!Toolkit.getToolkit().canStartNestedEventLoop()) {
+            throw new IllegalStateException("showAndWait is not allowed during animation or layout processing");
+        }
+
         Event.fireEvent(this, new DialogEvent(this, DialogEvent.DIALOG_SHOWING));
         if( getWidth() == Double.NaN && getHeight() == Double.NaN ) {
             dialog.sizeToScene();
--- a/modules/controls/src/test/java/javafx/scene/chart/AreaChartTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/test/java/javafx/scene/chart/AreaChartTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -88,51 +88,6 @@
         return sb;
     }
 
-    @Test
-    public void testSeriesRemove() {
-        startApp();
-        ac.getData().addAll(series1);
-        pulse();
-        // 5 symbols and 1 area group
-        assertEquals(6, ac.getPlotChildren().size());
-        ac.getData().remove(0);
-        pulse();
-        assertEquals(0, ac.getPlotChildren().size());
-    }
-
-    @Test
-    public void testSeriesRemoveWithoutSymbols() {
-        startApp();
-        ac.setCreateSymbols(false);
-        ac.getData().addAll(series1);
-        pulse();
-        // 1 area group
-        assertEquals(1, ac.getPlotChildren().size());
-        ac.getData().remove(0);
-        pulse();
-        assertEquals(0, ac.getPlotChildren().size());
-    }
-
-    @Test
-    public void testSeriesRemoveWithoutSymbolsAnimated_rt_22124() {
-        startApp();
-        ac.setCreateSymbols(false);
-        ac.getData().addAll(series1);
-        pulse();
-        // 1 area group
-        assertEquals(1, ac.getPlotChildren().size());
-
-        ac.setAnimated(true);
-        ControlTestUtils.runWithExceptionHandler(() -> {
-            ac.getData().remove(0);
-        });
-        toolkit.setAnimationTime(200);
-        assertEquals(1, ac.getPlotChildren().size());
-        assertEquals(0.5, ac.getPlotChildren().get(0).getOpacity(), 0.0);
-        toolkit.setAnimationTime(400);
-        assertEquals(0, ac.getPlotChildren().size());
-    }
-
     @Test @Ignore
     public void testDataItemRemove() {
         startApp();
@@ -169,19 +124,4 @@
          pulse();
          assertEquals(5, countSymbols(ac, "chart-area-symbol"));
      }
-
-    @Test
-    public void testDataWithoutSymbolsAddWithAnimation_rt_39353() {
-        startApp();
-        ac.getData().addAll(series1);
-        ac.setAnimated(true);
-        ac.setCreateSymbols(false);
-        series1.getData().add(new XYChart.Data(40d,10d));
-        ControlTestUtils.runWithExceptionHandler(() -> {
-            toolkit.setAnimationTime(0);
-            // check remove just in case
-            series1.getData().remove(0);
-            toolkit.setAnimationTime(800);
-        });
-    }
 }
--- a/modules/controls/src/test/java/javafx/scene/chart/LineChartTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/test/java/javafx/scene/chart/LineChartTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -68,51 +68,6 @@
     }
 
     @Test
-    public void testSeriesRemove() {
-        startApp();
-        lineChart.getData().addAll(series1);
-        pulse();
-        // 5 symbols and 1 line node
-        assertEquals(6, lineChart.getPlotChildren().size());
-        lineChart.getData().remove(0);
-        pulse();
-        assertEquals(0, lineChart.getPlotChildren().size());
-    }
-
-    @Test
-    public void testSeriesRemoveWithoutSymbols() {
-        startApp();
-        lineChart.setCreateSymbols(false);
-        lineChart.getData().addAll(series1);
-        pulse();
-        // 1 line node
-        assertEquals(1, lineChart.getPlotChildren().size());
-        lineChart.getData().remove(0);
-        pulse();
-        assertEquals(0, lineChart.getPlotChildren().size());
-    }
-
-    @Test
-    public void testSeriesRemoveWithoutSymbolsAnimated_rt_22124() {
-        startApp();
-        lineChart.setCreateSymbols(false);
-        lineChart.getData().addAll(series1);
-        pulse();
-        // 1 line node
-        assertEquals(1, lineChart.getPlotChildren().size());
-
-        lineChart.setAnimated(true);
-        ControlTestUtils.runWithExceptionHandler(() -> {
-            lineChart.getData().remove(0);
-        });
-        toolkit.setAnimationTime(450);
-        assertEquals(1, lineChart.getPlotChildren().size());
-        assertEquals(0.5, lineChart.getPlotChildren().get(0).getOpacity(), 0.0);
-        toolkit.setAnimationTime(900);
-        assertEquals(0, lineChart.getPlotChildren().size());
-    }
-
-    @Test
     public void testCreateSymbols() {
         startApp();
         lineChart.setCreateSymbols(false);
--- a/modules/controls/src/test/java/javafx/scene/chart/StackedAreaChartTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/controls/src/test/java/javafx/scene/chart/StackedAreaChartTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -99,51 +99,6 @@
     
     }
 
-    @Test
-    public void testSeriesRemove() {
-        startApp();
-        ac.getData().addAll(series1);
-        pulse();
-        // 5 symbols and 1 area group
-        assertEquals(6, ac.getPlotChildren().size());
-        ac.getData().remove(0);
-        pulse();
-        assertEquals(0, ac.getPlotChildren().size());
-    }
-
-    @Test
-    public void testSeriesRemoveWithoutSymbols() {
-        startApp();
-        ac.setCreateSymbols(false);
-        ac.getData().addAll(series1);
-        pulse();
-        // 1 area group
-        assertEquals(1, ac.getPlotChildren().size());
-        ac.getData().remove(0);
-        pulse();
-        assertEquals(0, ac.getPlotChildren().size());
-    }
-
-    @Test
-    public void testSeriesRemoveWithoutSymbolsAnimated_rt_22124() {
-        startApp();
-        ac.setCreateSymbols(false);
-        ac.getData().addAll(series1);
-        pulse();
-        // 1 area group
-        assertEquals(1, ac.getPlotChildren().size());
-
-        ac.setAnimated(true);
-        ControlTestUtils.runWithExceptionHandler(() -> {
-            ac.getData().remove(0);
-        });
-        toolkit.setAnimationTime(200);
-        assertEquals(1, ac.getPlotChildren().size());
-        assertEquals(0.5, ac.getPlotChildren().get(0).getOpacity(), 0.0);
-        toolkit.setAnimationTime(400);
-        assertEquals(0, ac.getPlotChildren().size());
-    }
-
     @Test @Ignore
     public void testDataItemRemove() {
         startApp();
@@ -453,19 +408,4 @@
         assertEquals(2, yAxis.dataMinValue, 1e-100);
         assertEquals(15, yAxis.dataMaxValue, 1e-100);
     }
-    
-    @Test
-    public void testDataWithoutSymbolsAddWithAnimation_rt_39353() {
-        startApp();
-        ac.getData().addAll(series1);
-        ac.setAnimated(true);
-        ac.setCreateSymbols(false);
-        series1.getData().add(new XYChart.Data(40d,10d));
-        ControlTestUtils.runWithExceptionHandler(() -> {
-            toolkit.setAnimationTime(0);
-            // check remove just in case
-            series1.getData().remove(0);
-            toolkit.setAnimationTime(800);
-        });
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/src/test/java/javafx/scene/chart/XYNumberChartsTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 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.scene.chart;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class XYNumberChartsTest extends XYNumberChartsTestBase {
+    private Class chartClass;
+    int nodesPerSeries;
+
+    @Parameterized.Parameters
+    public static Collection implementations() {
+        return Arrays.asList(new Object[][] {
+            { AreaChart.class, 1, },
+            { BubbleChart.class, 0, },
+            { LineChart.class, 1, },
+            { ScatterChart.class, 0, },
+            { StackedAreaChart.class, 1, },
+        });
+    }
+
+    public XYNumberChartsTest(Class chartClass, int nodesPerSeries) {
+        this.chartClass = chartClass;
+        this.nodesPerSeries = nodesPerSeries;
+    }
+
+    @Override
+    protected Chart createChart() {
+        try {
+            chart = (XYChart<Number, Number>) chartClass.getConstructor(Axis.class, Axis.class).
+                newInstance(new NumberAxis(), new NumberAxis());
+        } catch (InvocationTargetException e) {
+            throw new AssertionError(e.getCause());
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+        return chart;
+    }
+
+    @Test
+    public void testSeriesClearAnimated_rt_40632() {
+        checkSeriesClearAnimated_rt_40632();
+    }
+
+    @Test
+    public void testSeriesRemove() {
+        checkSeriesRemove(2 + nodesPerSeries);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/src/test/java/javafx/scene/chart/XYNumberChartsTestBase.java	Fri Jun 05 17:39:54 2015 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 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.scene.chart;
+
+import com.sun.javafx.scene.control.infrastructure.ControlTestUtils;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import static org.junit.Assert.assertEquals;
+
+abstract public class XYNumberChartsTestBase extends XYChartTestBase {
+    XYChart<Number, Number> chart;
+    ObservableList<XYChart.Data<Number, Number>> seriesData = FXCollections.observableArrayList(
+            new XYChart.Data<>(10, 10),
+            new XYChart.Data<>(20, 20)
+    );
+    XYChart.Series<Number, Number> series = new XYChart.Series<>(seriesData);
+
+    protected void startAppWithSeries() {
+        chart.getData().addAll(series);
+        startApp();
+    }
+
+    void checkSeriesClearAnimated_rt_40632() {
+        startAppWithSeries();
+        chart.setAnimated(true);
+        ControlTestUtils.runWithExceptionHandler(() -> {
+            series.getData().clear();
+        });
+    }
+
+    void checkSeriesRemove(int expectedNodesCount) {
+        startAppWithSeries();
+        assertEquals(expectedNodesCount, chart.getPlotChildren().size());
+        chart.getData().remove(0);
+        pulse();
+        assertEquals(0, chart.getPlotChildren().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/src/test/java/javafx/scene/chart/XYNumberLineChartsTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 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.scene.chart;
+
+import com.sun.javafx.scene.control.infrastructure.ControlTestUtils;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class XYNumberLineChartsTest extends XYNumberChartsTestBase {
+    private Class chartClass;
+    private int seriesFadeOutTime;
+
+    @Parameterized.Parameters
+    public static Collection implementations() {
+        return Arrays.asList(new Object[][] {
+            { AreaChart.class, 400 },
+            { LineChart.class, 900 },
+            { StackedAreaChart.class, 400 }
+        });
+    }
+
+    public XYNumberLineChartsTest(Class chartClass, int seriesFadeOutTime) {
+        this.chartClass = chartClass;
+        this.seriesFadeOutTime = seriesFadeOutTime;
+    }
+
+    @Override
+    protected Chart createChart() {
+        try {
+            chart = (XYChart<Number, Number>) chartClass.getConstructor(Axis.class, Axis.class).
+                newInstance(new NumberAxis(), new NumberAxis());
+            Method setCreateSymbolsMethod = chartClass.getMethod("setCreateSymbols", Boolean.TYPE);
+            setCreateSymbolsMethod.invoke(chart, false);
+        } catch (InvocationTargetException e) {
+            throw new AssertionError(e.getCause());
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+        return chart;
+    }
+
+    @Test
+    public void testSeriesClearAnimatedWithoutSymbols_rt_40632() {
+        checkSeriesClearAnimated_rt_40632();
+    }
+
+    @Test
+    public void testSeriesRemoveWithoutSymbols() {
+        // 1 area group
+        checkSeriesRemove(1);
+    }
+
+    @Test
+    public void testSeriesRemoveWithoutSymbolsAnimated_rt_22124() {
+        startAppWithSeries();
+        // 1 area group
+        assertEquals(1, chart.getPlotChildren().size());
+
+        chart.setAnimated(true);
+        ControlTestUtils.runWithExceptionHandler(() -> {
+            // tests RT-22124
+            chart.getData().remove(0);
+        });
+        toolkit.setAnimationTime(seriesFadeOutTime/2);
+        assertEquals(1, chart.getPlotChildren().size());
+        // tests RT-46086
+        assertEquals(0.5, chart.getPlotChildren().get(0).getOpacity(), 0.0);
+        toolkit.setAnimationTime(seriesFadeOutTime);
+        assertEquals(0, chart.getPlotChildren().size());
+    }
+
+    @Test
+    public void testDataWithoutSymbolsAddWithAnimation_rt_39353() {
+        startAppWithSeries();
+        chart.setAnimated(true);
+        series.getData().add(new XYChart.Data<>(30, 30));
+        ControlTestUtils.runWithExceptionHandler(() -> {
+            toolkit.setAnimationTime(0);
+        });
+    }
+}
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java	Fri Jun 05 17:39:54 2015 -0700
@@ -234,7 +234,7 @@
         if (existingSetting == null) {
             attr.put(new Attributes.Name("Permissions"),
                     Boolean.TRUE.equals(createJarParams.allPermissions) ? "all-permissions" : "sandbox");
-        } else if (!Boolean.valueOf(existingSetting).equals(createJarParams.allPermissions)) { 
+        } else if (createJarParams.allPermissions != null && !Boolean.valueOf(existingSetting).equals(createJarParams.allPermissions)) { 
             throw new PackagerException(
                 "ERR_ContradictorySetting", "Permissions"); 
         }
@@ -244,7 +244,7 @@
             if (createJarParams.codebase != null) {
                 attr.put(new Attributes.Name("Codebase"), createJarParams.codebase);
             }
-        } else if (!existingSetting.equals(createJarParams.codebase)) {
+        } else if (createJarParams.codebase != null && !existingSetting.equals(createJarParams.codebase)) {
             throw new PackagerException(
                     "ERR_ContradictorySetting", "Codebase");
         }
--- a/modules/fxpackager/src/test/java/com/sun/javafx/tools/ant/FXJarTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/fxpackager/src/test/java/com/sun/javafx/tools/ant/FXJarTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -165,9 +165,8 @@
         fxjar.execute();
     }
 
-    @Test(expected = BuildException.class)
+    @Test()
     public void codebaseManifestTest() throws IOException, ManifestException {
-
         org.apache.tools.ant.taskdefs.Manifest mf = fxjar.createManifest();
         mf.addConfiguredAttribute(new org.apache.tools.ant.taskdefs.Manifest.Attribute(
                 CODEBASE_ATTRIBUTE_NAME, CODEBASE_ATTRIBUTE_VALUE));
--- a/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java	Fri Jun 05 17:39:54 2015 -0700
@@ -120,6 +120,16 @@
 
 final public class StyleManager {
 
+    /**
+     * Global lock object for the StyleManager. StyleManager is a singleton,
+     * which loads CSS stylesheets and manages style caches for all scenes.
+     * It needs to be thread-safe since a Node or Scene can be constructed and
+     * load its stylesheets on an arbitrary thread, meaning that multiple Scenes
+     * can load or apply their stylesheets concurrently. The global lock is used
+     * to serialize access to the various state in the StyleManager.
+     */
+    private static final Object styleLock = new Object();
+
     private static PlatformLogger LOGGER;
     private static PlatformLogger getLogger() {
         if (LOGGER == null) {
@@ -174,16 +184,18 @@
 
         if (root == null) return null;
 
-        CacheContainer container = cacheContainerMap.get(root);
-        if (container == null) {
-            container = new CacheContainer();
-            cacheContainerMap.put(root, container);
+        synchronized (styleLock) {
+            CacheContainer container = cacheContainerMap.get(root);
+            if (container == null) {
+                container = new CacheContainer();
+                cacheContainerMap.put(root, container);
+            }
+
+            return container;
         }
+    }
 
-        return container;
-
-    }
-    /** 
+    /**
      * StyleHelper uses this cache but it lives here so it can be cleared
      * when style-sheets change.
      */
@@ -203,11 +215,11 @@
 
         return sharedCache;
     }
-    
+
     public StyleMap getStyleMap(Styleable styleable, SubScene subScene, int smapId) {
 
         if (smapId == -1) return StyleMap.EMPTY_MAP;
-        
+
         CacheContainer container = getCacheContainer(styleable, subScene);
         if (container == null) return StyleMap.EMPTY_MAP;
 
@@ -420,52 +432,53 @@
 
         forget(scene.getRoot());
 
-        //
-        // if this scene has user-agent stylesheets, clean up the userAgentStylesheetContainers list
-        //
-        String sceneUserAgentStylesheet = null;
-        if ((scene.getUserAgentStylesheet() != null) &&
-                (!(sceneUserAgentStylesheet = scene.getUserAgentStylesheet().trim()).isEmpty())) {
+        synchronized (styleLock) {
+            //
+            // if this scene has user-agent stylesheets, clean up the userAgentStylesheetContainers list
+            //
+            String sceneUserAgentStylesheet = null;
+            if ((scene.getUserAgentStylesheet() != null) &&
+                    (!(sceneUserAgentStylesheet = scene.getUserAgentStylesheet().trim()).isEmpty())) {
 
-            for(int n=userAgentStylesheetContainers.size()-1; 0<=n; --n) {
-                StylesheetContainer container = userAgentStylesheetContainers.get(n);
-                if (sceneUserAgentStylesheet.equals(container.fname)) {
-                    container.parentUsers.remove(scene.getRoot());
-                    if (container.parentUsers.list.size() == 0) {
-                        userAgentStylesheetContainers.remove(n);
+                for(int n=userAgentStylesheetContainers.size()-1; 0<=n; --n) {
+                    StylesheetContainer container = userAgentStylesheetContainers.get(n);
+                    if (sceneUserAgentStylesheet.equals(container.fname)) {
+                        container.parentUsers.remove(scene.getRoot());
+                        if (container.parentUsers.list.size() == 0) {
+                            userAgentStylesheetContainers.remove(n);
+                        }
                     }
                 }
             }
-        }
 
-        //
-        // remove any parents belonging to this scene from the stylesheetContainerMap
-        //
-        Set<Entry<String,StylesheetContainer>> stylesheetContainers = stylesheetContainerMap.entrySet();
-        Iterator<Entry<String,StylesheetContainer>> iter = stylesheetContainers.iterator();
+            //
+            // remove any parents belonging to this scene from the stylesheetContainerMap
+            //
+            Set<Entry<String,StylesheetContainer>> stylesheetContainers = stylesheetContainerMap.entrySet();
+            Iterator<Entry<String,StylesheetContainer>> iter = stylesheetContainers.iterator();
 
-        while(iter.hasNext()) {
+            while(iter.hasNext()) {
 
-            Entry<String,StylesheetContainer> entry = iter.next();
-            StylesheetContainer container = entry.getValue();
+                Entry<String,StylesheetContainer> entry = iter.next();
+                StylesheetContainer container = entry.getValue();
 
-            Iterator<Reference<Parent>> parentIter = container.parentUsers.list.iterator();
-            while (parentIter.hasNext()) {
+                Iterator<Reference<Parent>> parentIter = container.parentUsers.list.iterator();
+                while (parentIter.hasNext()) {
 
-                Reference<Parent> ref = parentIter.next();
-                Parent _parent = ref.get();
+                    Reference<Parent> ref = parentIter.next();
+                    Parent _parent = ref.get();
 
-                if (_parent == null || _parent.getScene() == scene || _parent.getScene() == null) {
-                    ref.clear();
-                    parentIter.remove();
+                    if (_parent == null || _parent.getScene() == scene || _parent.getScene() == null) {
+                        ref.clear();
+                        parentIter.remove();
+                    }
+                }
+
+                if (container.parentUsers.list.isEmpty()) {
+                    iter.remove();
                 }
             }
-
-            if (container.parentUsers.list.isEmpty()) {
-                iter.remove();
-            }
         }
-
     }
 
     /**
@@ -473,32 +486,33 @@
      */
     public void stylesheetsChanged(Scene scene, Change<String> c) {
 
-        // Clear the cache so the cache will be rebuilt.
-        Set<Entry<Parent,CacheContainer>> entrySet = cacheContainerMap.entrySet();
-        for(Entry<Parent,CacheContainer> entry : entrySet) {
-            Parent parent = entry.getKey();
-            CacheContainer container = entry.getValue();
-            if (parent.getScene() == scene) {
-                container.clearCache();
+        synchronized (styleLock) {
+            // Clear the cache so the cache will be rebuilt.
+            Set<Entry<Parent,CacheContainer>> entrySet = cacheContainerMap.entrySet();
+            for(Entry<Parent,CacheContainer> entry : entrySet) {
+                Parent parent = entry.getKey();
+                CacheContainer container = entry.getValue();
+                if (parent.getScene() == scene) {
+                    container.clearCache();
+                }
+
             }
 
-        }
+            c.reset();
+            while(c.next()) {
+                if (c.wasRemoved()) {
+                    for (String fname : c.getRemoved()) {
+                        stylesheetRemoved(scene, fname);
 
-        c.reset();
-        while(c.next()) {
-            if (c.wasRemoved()) {
-                for (String fname : c.getRemoved()) {
-                    stylesheetRemoved(scene, fname);
+                        StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
+                        if (stylesheetContainer != null) {
+                            stylesheetContainer.invalidateChecksum();
+                        }
 
-                    StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
-                    if (stylesheetContainer != null) {
-                        stylesheetContainer.invalidateChecksum();
                     }
-
                 }
             }
         }
-
     }
 
     private void stylesheetRemoved(Scene scene, String fname) {
@@ -513,63 +527,67 @@
 
         if (parent == null) return;
 
-        // RT-34863 - clean up CSS cache when Parent is removed from scene-graph
-        Set<Entry<Parent, CacheContainer>> entrySet = cacheContainerMap.entrySet();
-        Iterator<Entry<Parent, CacheContainer>> iterator = entrySet.iterator();
-        while (iterator.hasNext()) {
-            Entry<Parent, CacheContainer> entry = iterator.next();
-            Parent key = entry.getKey();
-            CacheContainer container = entry.getValue();
-            if (parent == key) {
-                iterator.remove();
-                container.clearCache();
+        synchronized (styleLock) {
+            // RT-34863 - clean up CSS cache when Parent is removed from scene-graph
+            Set<Entry<Parent, CacheContainer>> entrySet = cacheContainerMap.entrySet();
+            Iterator<Entry<Parent, CacheContainer>> iterator = entrySet.iterator();
+            while (iterator.hasNext()) {
+                Entry<Parent, CacheContainer> entry = iterator.next();
+                Parent key = entry.getKey();
+                CacheContainer container = entry.getValue();
+                if (parent == key) {
+                    iterator.remove();
+                    container.clearCache();
+                }
             }
+
+            final List<String> stylesheets = parent.getStylesheets();
+            if (stylesheets != null && !stylesheets.isEmpty()) {
+                for (String fname : stylesheets) {
+                    stylesheetRemoved(parent, fname);
+                }
+            }
+
+            Iterator<Entry<String,StylesheetContainer>> containerIterator = stylesheetContainerMap.entrySet().iterator();
+            while (containerIterator.hasNext()) {
+                Entry<String,StylesheetContainer> entry = containerIterator.next();
+                StylesheetContainer container = entry.getValue();
+                container.parentUsers.remove(parent);
+                if (container.parentUsers.list.isEmpty()) {
+
+                    containerIterator.remove();
+
+                    if (container.selectorPartitioning != null) {
+                        container.selectorPartitioning.reset();
+                    }
+
+
+                    // clean up image cache by removing images from the cache that
+                    // might have come from this stylesheet
+                    final String fname = container.fname;
+                    cleanUpImageCache(fname);
+                }
+            }
+
+            // Do not iterate over children since this method will be called on each from Parent#scenesChanged
         }
-
-        final List<String> stylesheets = parent.getStylesheets();
-        if (stylesheets != null && !stylesheets.isEmpty()) {
-            for (String fname : stylesheets) {
-                stylesheetRemoved(parent, fname);
-            }
-        }
-
-        Iterator<Entry<String,StylesheetContainer>> containerIterator = stylesheetContainerMap.entrySet().iterator();
-        while (containerIterator.hasNext()) {
-            Entry<String,StylesheetContainer> entry = containerIterator.next();
-            StylesheetContainer container = entry.getValue();
-            container.parentUsers.remove(parent);
-            if (container.parentUsers.list.isEmpty()) {
-
-                containerIterator.remove();
-
-                if (container.selectorPartitioning != null) {
-                    container.selectorPartitioning.reset();
-                }
-
-
-                // clean up image cache by removing images from the cache that
-                // might have come from this stylesheet
-                final String fname = container.fname;
-                cleanUpImageCache(fname);
-            }
-        }
-
-        // Do not iterate over children since this method will be called on each from Parent#scenesChanged
     }
 
     /**
      * called from Parent's stylesheets property's onChanged method
      */
     public void stylesheetsChanged(Parent parent, Change<String> c) {
-        c.reset();
-        while(c.next()) {
-            if (c.wasRemoved()) {
-                for (String fname : c.getRemoved()) {
-                    stylesheetRemoved(parent, fname);
+        synchronized (styleLock) {
+            c.reset();
+            while(c.next()) {
+                if (c.wasRemoved()) {
+                    for (String fname : c.getRemoved()) {
+                        stylesheetRemoved(parent, fname);
 
-                    StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
-                    if (stylesheetContainer != null) {
-                        stylesheetContainer.invalidateChecksum();
+                        StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
+                        if (stylesheetContainer != null) {
+                            stylesheetContainer.invalidateChecksum();
+                        }
                     }
                 }
             }
@@ -578,14 +596,16 @@
 
     private void stylesheetRemoved(Parent parent, String fname) {
 
-        StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
+        synchronized (styleLock) {
+            StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
 
-        if (stylesheetContainer == null) return;
+            if (stylesheetContainer == null) return;
 
-        stylesheetContainer.parentUsers.remove(parent);
+            stylesheetContainer.parentUsers.remove(parent);
 
-        if (stylesheetContainer.parentUsers.list.isEmpty()) {
-            removeStylesheetContainer(stylesheetContainer);
+            if (stylesheetContainer.parentUsers.list.isEmpty()) {
+                removeStylesheetContainer(stylesheetContainer);
+            }
         }
     }
 
@@ -600,62 +620,64 @@
         if (subSceneRoot == null) return;
         forget(subSceneRoot);
 
-        //
-        // if this scene has user-agent stylesheets, clean up the userAgentStylesheetContainers list
-        //
-        String sceneUserAgentStylesheet = null;
-        if ((subScene.getUserAgentStylesheet() != null) &&
-                (!(sceneUserAgentStylesheet = subScene.getUserAgentStylesheet().trim()).isEmpty())) {
+        synchronized (styleLock) {
+            //
+            // if this scene has user-agent stylesheets, clean up the userAgentStylesheetContainers list
+            //
+            String sceneUserAgentStylesheet = null;
+            if ((subScene.getUserAgentStylesheet() != null) &&
+                    (!(sceneUserAgentStylesheet = subScene.getUserAgentStylesheet().trim()).isEmpty())) {
 
-            Iterator<StylesheetContainer> iterator = userAgentStylesheetContainers.iterator();
-            while(iterator.hasNext()) {
-                StylesheetContainer container = iterator.next();
-                if (sceneUserAgentStylesheet.equals(container.fname)) {
-                    container.parentUsers.remove(subScene.getRoot());
-                    if (container.parentUsers.list.size() == 0) {
-                        iterator.remove();
-                    }
-                }
-            }
-        }
-
-        //
-        // remove any parents belonging to this SubScene from the stylesheetContainerMap
-        //
-        // copy the list to avoid concurrent mod.
-        List<StylesheetContainer> stylesheetContainers = new ArrayList<>(stylesheetContainerMap.values());
-
-        Iterator<StylesheetContainer> iter = stylesheetContainers.iterator();
-
-        while(iter.hasNext()) {
-
-            StylesheetContainer container = iter.next();
-
-            Iterator<Reference<Parent>> parentIter = container.parentUsers.list.iterator();
-            while (parentIter.hasNext()) {
-
-                final Reference<Parent> ref = parentIter.next();
-                final Parent _parent = ref.get();
-
-                if (_parent != null) {
-                    // if this stylesheet refererent is a child of this subscene, nuke it.
-                    Parent p = _parent;
-                    while (p != null) {
-                        if (subSceneRoot == p.getParent()) {
-                            ref.clear();
-                            parentIter.remove();
-                            forget(_parent); // _parent, not p!
-                            break;
+                Iterator<StylesheetContainer> iterator = userAgentStylesheetContainers.iterator();
+                while(iterator.hasNext()) {
+                    StylesheetContainer container = iterator.next();
+                    if (sceneUserAgentStylesheet.equals(container.fname)) {
+                        container.parentUsers.remove(subScene.getRoot());
+                        if (container.parentUsers.list.size() == 0) {
+                            iterator.remove();
                         }
-                        p = p.getParent();
                     }
                 }
             }
 
-            // forget(_parent) will remove the container if the parentUser's list is empty
-            // if (container.parentUsers.list.isEmpty()) {
-            //    iter.remove();
-            // }
+            //
+            // remove any parents belonging to this SubScene from the stylesheetContainerMap
+            //
+            // copy the list to avoid concurrent mod.
+            List<StylesheetContainer> stylesheetContainers = new ArrayList<>(stylesheetContainerMap.values());
+
+            Iterator<StylesheetContainer> iter = stylesheetContainers.iterator();
+
+            while(iter.hasNext()) {
+
+                StylesheetContainer container = iter.next();
+
+                Iterator<Reference<Parent>> parentIter = container.parentUsers.list.iterator();
+                while (parentIter.hasNext()) {
+
+                    final Reference<Parent> ref = parentIter.next();
+                    final Parent _parent = ref.get();
+
+                    if (_parent != null) {
+                        // if this stylesheet refererent is a child of this subscene, nuke it.
+                        Parent p = _parent;
+                        while (p != null) {
+                            if (subSceneRoot == p.getParent()) {
+                                ref.clear();
+                                parentIter.remove();
+                                forget(_parent); // _parent, not p!
+                                break;
+                            }
+                            p = p.getParent();
+                        }
+                    }
+                }
+
+                // forget(_parent) will remove the container if the parentUser's list is empty
+                // if (container.parentUsers.list.isEmpty()) {
+                //    iter.remove();
+                // }
+            }
         }
 
     }
@@ -664,64 +686,65 @@
 
         if (stylesheetContainer == null) return;
 
-        final String fname = stylesheetContainer.fname;
+        synchronized (styleLock) {
+            final String fname = stylesheetContainer.fname;
 
-        stylesheetContainerMap.remove(fname);
+            stylesheetContainerMap.remove(fname);
 
-        if (stylesheetContainer.selectorPartitioning != null) {
-            stylesheetContainer.selectorPartitioning.reset();
-        }
-
-        // if container has no references, then remove it
-        for(Entry<Parent,CacheContainer> entry : cacheContainerMap.entrySet()) {
-
-            CacheContainer container = entry.getValue();
-            if (container == null || container.cacheMap == null || container.cacheMap.isEmpty()) {
-                continue;
+            if (stylesheetContainer.selectorPartitioning != null) {
+                stylesheetContainer.selectorPartitioning.reset();
             }
 
-            List<List<String>> entriesToRemove = new ArrayList<>();
+            // if container has no references, then remove it
+            for(Entry<Parent,CacheContainer> entry : cacheContainerMap.entrySet()) {
 
-            for (Entry<List<String>, Map<Key,Cache>> cacheMapEntry : container.cacheMap.entrySet()) {
-                List<String> cacheMapKey = cacheMapEntry.getKey();
-                if (cacheMapKey != null ? cacheMapKey.contains(fname) : fname == null) {
-                    entriesToRemove.add(cacheMapKey);
+                CacheContainer container = entry.getValue();
+                if (container == null || container.cacheMap == null || container.cacheMap.isEmpty()) {
+                    continue;
+                }
+
+                List<List<String>> entriesToRemove = new ArrayList<>();
+
+                for (Entry<List<String>, Map<Key,Cache>> cacheMapEntry : container.cacheMap.entrySet()) {
+                    List<String> cacheMapKey = cacheMapEntry.getKey();
+                    if (cacheMapKey != null ? cacheMapKey.contains(fname) : fname == null) {
+                        entriesToRemove.add(cacheMapKey);
+                    }
+                }
+
+                if (!entriesToRemove.isEmpty()) {
+                    for (List<String> cacheMapKey : entriesToRemove) {
+                        Map<Key,Cache> cacheEntry = container.cacheMap.remove(cacheMapKey);
+                        if (cacheEntry != null) {
+                            cacheEntry.clear();
+                        }
+                    }
                 }
             }
 
-            if (!entriesToRemove.isEmpty()) {
-                for (List<String> cacheMapKey : entriesToRemove) {
-                    Map<Key,Cache> cacheEntry = container.cacheMap.remove(cacheMapKey);
-                    if (cacheEntry != null) {
-                        cacheEntry.clear();
-                    }
+            // clean up image cache by removing images from the cache that
+            // might have come from this stylesheet
+            cleanUpImageCache(fname);
+
+            final List<Reference<Parent>> parentList = stylesheetContainer.parentUsers.list;
+
+            for (int n=parentList.size()-1; 0<=n; --n) {
+
+                final Reference<Parent> ref = parentList.remove(n);
+                final Parent parent = ref.get();
+                ref.clear();
+                if (parent == null || parent.getScene() == null) {
+                    continue;
                 }
+
+                //
+                // tell parent it needs to reapply css
+                // No harm is done if parent is in a scene that has had
+                // impl_reapplyCSS called on the root.
+                //
+                parent.impl_reapplyCSS();
             }
         }
-
-        // clean up image cache by removing images from the cache that
-        // might have come from this stylesheet
-        cleanUpImageCache(fname);
-
-        final List<Reference<Parent>> parentList = stylesheetContainer.parentUsers.list;
-
-        for (int n=parentList.size()-1; 0<=n; --n) {
-
-            final Reference<Parent> ref = parentList.remove(n);
-            final Parent parent = ref.get();
-            ref.clear();
-            if (parent == null || parent.getScene() == null) {
-                continue;
-            }
-
-            //
-            // tell parent it needs to reapply css
-            // No harm is done if parent is in a scene that has had
-            // impl_reapplyCSS called on the root.
-            //
-            parent.impl_reapplyCSS();
-        }
-
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -730,84 +753,88 @@
     //
     ////////////////////////////////////////////////////////////////////////////
 
-    final Map<String,Image> imageCache = new HashMap<String,Image>();
+    private final Map<String,Image> imageCache = new HashMap<String,Image>();
 
     public Image getCachedImage(String url) {
 
-        Image image = null;
-        if (imageCache.containsKey(url)) {
+        synchronized (styleLock) {
+            Image image = null;
+            if (imageCache.containsKey(url)) {
 
-            image = imageCache.get(url);
+                image = imageCache.get(url);
 
-        } else {
+            } else {
 
-            try {
+                try {
 
-                image = new Image(url);
+                    image = new Image(url);
 
-                // RT-31865
-                if (image.isError()) {
+                    // RT-31865
+                    if (image.isError()) {
 
+                        final PlatformLogger logger = getLogger();
+                        if (logger != null && logger.isLoggable(Level.WARNING)) {
+                            logger.warning("Error loading image: " + url);
+                        }
+
+                        image = null;
+                    }
+
+                    imageCache.put(url, image);
+
+                } catch (IllegalArgumentException iae) {
+                    // url was empty!
                     final PlatformLogger logger = getLogger();
                     if (logger != null && logger.isLoggable(Level.WARNING)) {
-                        logger.warning("Error loading image: " + url);
+                        logger.warning(iae.getLocalizedMessage());
                     }
 
-                    image = null;
-                }
-
-                imageCache.put(url, image);
-
-            } catch (IllegalArgumentException iae) {
-                // url was empty!
-                final PlatformLogger logger = getLogger();
-                if (logger != null && logger.isLoggable(Level.WARNING)) {
-                    logger.warning(iae.getLocalizedMessage());
-                }
-
-            } catch (NullPointerException npe) {
-                // url was null!
-                final PlatformLogger logger = getLogger();
-                if (logger != null && logger.isLoggable(Level.WARNING)) {
-                    logger.warning(npe.getLocalizedMessage());
+                } catch (NullPointerException npe) {
+                    // url was null!
+                    final PlatformLogger logger = getLogger();
+                    if (logger != null && logger.isLoggable(Level.WARNING)) {
+                        logger.warning(npe.getLocalizedMessage());
+                    }
                 }
             }
+
+            return image;
         }
-
-        return image;
     }
 
     private void cleanUpImageCache(String imgFname) {
 
-        if (imgFname == null && imageCache.isEmpty()) return;
+        synchronized (styleLock) {
+            if (imgFname == null && imageCache.isEmpty()) return;
 
-        final String fname = imgFname.trim();
-        if (fname.isEmpty()) return;
+            final String fname = imgFname.trim();
+            if (fname.isEmpty()) return;
 
-        int len = fname.lastIndexOf('/');
-        final String path = (len > 0) ? fname.substring(0,len) : fname;
-        final int plen = path.length();
+            int len = fname.lastIndexOf('/');
+            final String path = (len > 0) ? fname.substring(0,len) : fname;
+            final int plen = path.length();
 
-        final String[] entriesToRemove = new String[imageCache.size()];
-        int count = 0;
+            final String[] entriesToRemove = new String[imageCache.size()];
+            int count = 0;
 
-        final Set<Entry<String, Image>> entrySet = imageCache.entrySet();
-        for(Entry<String, Image> entry : entrySet) {
+            final Set<Entry<String, Image>> entrySet = imageCache.entrySet();
+            for(Entry<String, Image> entry : entrySet) {
 
-            final String key = entry.getKey();
-            len = key.lastIndexOf('/');
-            final String kpath = (len > 0) ? key.substring(0, len) : key;
-            final int klen = kpath.length();
+                final String key = entry.getKey();
+                len = key.lastIndexOf('/');
+                final String kpath = (len > 0) ? key.substring(0, len) : key;
+                final int klen = kpath.length();
 
-            // if the longer path begins with the shorter path,
-            // then assume the image came from this path.
-            boolean match = (klen > plen) ? kpath.startsWith(path) : path.startsWith(kpath);
-            if (match) entriesToRemove[count++] = key;
+                // if the longer path begins with the shorter path,
+                // then assume the image came from this path.
+                boolean match = (klen > plen) ? kpath.startsWith(path) : path.startsWith(kpath);
+                if (match) entriesToRemove[count++] = key;
+            }
+
+            for (int n=0; n<count; n++) {
+                Image img = imageCache.remove(entriesToRemove[n]);
+            }
         }
-
-        for (int n=0; n<count; n++) {
-           Image img = imageCache.remove(entriesToRemove[n]);
-       }
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -1005,115 +1032,117 @@
 
     private static Stylesheet loadStylesheetUnPrivileged(final String fname) {
 
-        Boolean parse = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
+        synchronized (styleLock) {
+            Boolean parse = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> {
 
-            final String bss = System.getProperty("binary.css");
-            // binary.css is true by default.
-            // parse only if the file is not a .bss
-            // and binary.css is set to false
-            return (!fname.endsWith(".bss") && bss != null) ?
-                !Boolean.valueOf(bss) : Boolean.FALSE;
-        });
+                final String bss = System.getProperty("binary.css");
+                // binary.css is true by default.
+                // parse only if the file is not a .bss
+                // and binary.css is set to false
+                return (!fname.endsWith(".bss") && bss != null) ?
+                    !Boolean.valueOf(bss) : Boolean.FALSE;
+            });
 
-        try {
-            final String ext = (parse) ? (".css") : (".bss");
-            java.net.URL url = null;
-            Stylesheet stylesheet = null;
-            // check if url has extension, if not then just url as is and always parse as css text
-            if (!(fname.endsWith(".css") || fname.endsWith(".bss"))) {
-                url = getURL(fname);
-                parse = true;
-            } else {
-                final String name = fname.substring(0, fname.length() - 4);
+            try {
+                final String ext = (parse) ? (".css") : (".bss");
+                java.net.URL url = null;
+                Stylesheet stylesheet = null;
+                // check if url has extension, if not then just url as is and always parse as css text
+                if (!(fname.endsWith(".css") || fname.endsWith(".bss"))) {
+                    url = getURL(fname);
+                    parse = true;
+                } else {
+                    final String name = fname.substring(0, fname.length() - 4);
 
-                url = getURL(name+ext);
-                if (url == null && (parse = !parse)) {
-                    // If we failed to get the URL for the .bss file,
-                    // fall back to the .css file.
-                    // Note that 'parse' is toggled in the test.
-                    url = getURL(name+".css");
+                    url = getURL(name+ext);
+                    if (url == null && (parse = !parse)) {
+                        // If we failed to get the URL for the .bss file,
+                        // fall back to the .css file.
+                        // Note that 'parse' is toggled in the test.
+                        url = getURL(name+".css");
+                    }
+
+                    if ((url != null) && !parse) {
+
+                        try {
+                            // RT-36332: if loadBinary throws an IOException, make sure to try .css
+                            stylesheet = Stylesheet.loadBinary(url);
+                        } catch (IOException ioe) {
+                            stylesheet = null;
+                        }
+
+                        if (stylesheet == null && (parse = !parse)) {
+                            // If we failed to load the .bss file,
+                            // fall back to the .css file.
+                            // Note that 'parse' is toggled in the test.
+                            url = getURL(fname);
+                        }
+                    }
                 }
 
-                if ((url != null) && !parse) {
+                // either we failed to load the .bss file, or parse
+                // was set to true.
+                if ((url != null) && parse) {
+                    stylesheet = new CSSParser().parse(url);
+                }
 
-                    try {
-                        // RT-36332: if loadBinary throws an IOException, make sure to try .css
-                        stylesheet = Stylesheet.loadBinary(url);
-                    } catch (IOException ioe) {
-                        stylesheet = null;
+                if (stylesheet == null) {
+                    if (errors != null) {
+                        CssError error =
+                            new CssError(
+                                "Resource \""+fname+"\" not found."
+                            );
+                        errors.add(error);
                     }
-
-                    if (stylesheet == null && (parse = !parse)) {
-                        // If we failed to load the .bss file,
-                        // fall back to the .css file.
-                        // Note that 'parse' is toggled in the test.
-                        url = getURL(fname);
+                    if (getLogger().isLoggable(Level.WARNING)) {
+                        getLogger().warning(
+                            String.format("Resource \"%s\" not found.", fname)
+                        );
                     }
                 }
-            }
 
-            // either we failed to load the .bss file, or parse
-            // was set to true.
-            if ((url != null) && parse) {
-                stylesheet = CSSParser.getInstance().parse(url);
-            }
+                // load any fonts from @font-face
+                if (stylesheet != null) {
+                    faceLoop: for(FontFace fontFace: stylesheet.getFontFaces()) {
+                        for(FontFace.FontFaceSrc src: fontFace.getSources()) {
+                            if (src.getType() == FontFace.FontFaceSrcType.URL) {
+                                Font loadedFont = Font.loadFont(src.getSrc(),10);
+                                if (loadedFont == null) {
+                                    getLogger().info("Could not load @font-face font [" + src.getSrc() + "]");
+                                }
+                                continue faceLoop;
+                            }
+                        }
+                    }
+                }
 
-            if (stylesheet == null) {
+                return stylesheet;
+
+            } catch (FileNotFoundException fnfe) {
                 if (errors != null) {
                     CssError error =
                         new CssError(
-                            "Resource \""+fname+"\" not found."
+                            "Stylesheet \""+fname+"\" not found."
                         );
                     errors.add(error);
                 }
-                if (getLogger().isLoggable(Level.WARNING)) {
-                    getLogger().warning(
-                        String.format("Resource \"%s\" not found.", fname)
-                    );
+                if (getLogger().isLoggable(Level.INFO)) {
+                    getLogger().info("Could not find stylesheet: " + fname);//, fnfe);
+                }
+            } catch (IOException ioe) {
+                    if (errors != null) {
+                        CssError error =
+                            new CssError(
+                                "Could not load stylesheet: " + fname
+                            );
+                        errors.add(error);
+                    }
+                if (getLogger().isLoggable(Level.INFO)) {
+                    getLogger().info("Could not load stylesheet: " + fname);//, ioe);
                 }
             }
-
-            // load any fonts from @font-face
-            if (stylesheet != null) {
-                faceLoop: for(FontFace fontFace: stylesheet.getFontFaces()) {
-                    for(FontFace.FontFaceSrc src: fontFace.getSources()) {
-                        if (src.getType() == FontFace.FontFaceSrcType.URL) {
-                            Font loadedFont = Font.loadFont(src.getSrc(),10);
-                            if (loadedFont == null) {
-                                getLogger().info("Could not load @font-face font [" + src.getSrc() + "]");
-                            }
-                            continue faceLoop;
-                        }
-                    }
-                }
-            }
-
-            return stylesheet;
-
-        } catch (FileNotFoundException fnfe) {
-            if (errors != null) {
-                CssError error =
-                    new CssError(
-                        "Stylesheet \""+fname+"\" not found."
-                    );
-                errors.add(error);
-            }
-            if (getLogger().isLoggable(Level.INFO)) {
-                getLogger().info("Could not find stylesheet: " + fname);//, fnfe);
-            }
-        } catch (IOException ioe) {
-                if (errors != null) {
-                    CssError error =
-                        new CssError(
-                            "Could not load stylesheet: " + fname
-                        );
-                    errors.add(error);
-                }
-            if (getLogger().isLoggable(Level.INFO)) {
-                getLogger().info("Could not load stylesheet: " + fname);//, ioe);
-            }
+            return null;
         }
-        return null;
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -1134,58 +1163,59 @@
 
         if (urls == null || urls.size() == 0) return;
 
-        // Avoid resetting user agent stylesheets if they haven't changed.
-        if (urls.size() == platformUserAgentStylesheetContainers.size()) {
-            boolean isSame = true;
-            for (int n=0, nMax=urls.size(); n < nMax && isSame; n++) {
+        synchronized (styleLock) {
+            // Avoid resetting user agent stylesheets if they haven't changed.
+            if (urls.size() == platformUserAgentStylesheetContainers.size()) {
+                boolean isSame = true;
+                for (int n=0, nMax=urls.size(); n < nMax && isSame; n++) {
+
+                    final String url = urls.get(n);
+                    final String fname = (url != null) ? url.trim() : null;
+
+                    if (fname == null || fname.isEmpty()) break;
+
+                    StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                    // assignment in this conditional is intentional!
+                    if(isSame = fname.equals(container.fname)) {
+                        // don't use fname in calculateCheckSum since it is just the key to
+                        // find the StylesheetContainer. Rather, use the URL of the
+                        // stylesheet that was already loaded. For example, we could have
+                        // fname = "com/sun/javafx/scene/control/skin/modena/modena.css, but
+                        // the stylesheet URL could be jar:file://some/path/!com/sun/javafx/scene/control/skin/modena/modena.bss
+                        String stylesheetUrl = container.stylesheet.getUrl();
+                        byte[] checksum = calculateCheckSum(stylesheetUrl);
+                        isSame = Arrays.equals(checksum, container.checksum);
+                    }
+                }
+                if (isSame) return;
+            }
+
+            boolean modified = false;
+
+            for (int n=0, nMax=urls.size(); n < nMax; n++) {
 
                 final String url = urls.get(n);
                 final String fname = (url != null) ? url.trim() : null;
 
-                if (fname == null || fname.isEmpty()) break;
+                if (fname == null || fname.isEmpty()) continue;
 
-                StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-                // assignment in this conditional is intentional!
-                if(isSame = fname.equals(container.fname)) {
-                    // don't use fname in calculateCheckSum since it is just the key to
-                    // find the StylesheetContainer. Rather, use the URL of the
-                    // stylesheet that was already loaded. For example, we could have
-                    // fname = "com/sun/javafx/scene/control/skin/modena/modena.css, but
-                    // the stylesheet URL could be jar:file://some/path/!com/sun/javafx/scene/control/skin/modena/modena.bss
-                    String stylesheetUrl = container.stylesheet.getUrl();
-                    byte[] checksum = calculateCheckSum(stylesheetUrl);
-                    isSame = Arrays.equals(checksum, container.checksum);
+                if (!modified) {
+                    // we have at least one non null or non-empty url
+                    platformUserAgentStylesheetContainers.clear();
+                    modified = true;
+                }
+
+                if (n==0) {
+                    _setDefaultUserAgentStylesheet(fname);
+                } else {
+                    _addUserAgentStylesheet(fname);
                 }
             }
-            if (isSame) return;
-        }
 
-        boolean modified = false;
-
-        for (int n=0, nMax=urls.size(); n < nMax; n++) {
-
-            final String url = urls.get(n);
-            final String fname = (url != null) ? url.trim() : null;
-
-            if (fname == null || fname.isEmpty()) continue;
-
-            if (!modified) {
-                // we have at least one non null or non-empty url
-                platformUserAgentStylesheetContainers.clear();
-                modified = true;
-            }
-
-            if (n==0) {
-                _setDefaultUserAgentStylesheet(fname);
-            } else {
-                _addUserAgentStylesheet(fname);
+            if (modified) {
+                userAgentStylesheetsChanged();
             }
         }
-
-        if (modified) {
-            userAgentStylesheetsChanged();
-        }
-
     }
 
     /**
@@ -1212,35 +1242,39 @@
             return;
         }
 
-        // RT-20643
-        CssError.setCurrentScene(scene);
+        synchronized (styleLock) {
+            // RT-20643
+            CssError.setCurrentScene(scene);
 
-        if (_addUserAgentStylesheet(fname)) {
-            userAgentStylesheetsChanged();
+            if (_addUserAgentStylesheet(fname)) {
+                userAgentStylesheetsChanged();
+            }
+
+            // RT-20643
+            CssError.setCurrentScene(null);
         }
-
-        // RT-20643
-        CssError.setCurrentScene(null);
     }
 
     // fname is assumed to be non null and non empty
     private boolean _addUserAgentStylesheet(String fname) {
 
-        // if we already have this stylesheet, bail
-        for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
-            StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-            if (fname.equals(container.fname)) {
-                return false;
+        synchronized (styleLock) {
+            // if we already have this stylesheet, bail
+            for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
+                StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                if (fname.equals(container.fname)) {
+                    return false;
+                }
             }
+
+            final Stylesheet ua_stylesheet = loadStylesheet(fname);
+
+            if (ua_stylesheet == null) return false;
+
+            ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+            platformUserAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
+            return true;
         }
-
-        final Stylesheet ua_stylesheet = loadStylesheet(fname);
-
-        if (ua_stylesheet == null) return false;
-
-        ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-        platformUserAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
-        return true;
     }
 
     /**
@@ -1259,27 +1293,28 @@
         String url = ua_stylesheet.getUrl();
         final String fname = url != null ? url.trim() : "";
 
-        // if we already have this stylesheet, bail
-        for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
-            StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-            if (fname.equals(container.fname)) {
-                return;
+        synchronized (styleLock) {
+            // if we already have this stylesheet, bail
+            for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
+                StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                if (fname.equals(container.fname)) {
+                    return;
+                }
             }
+
+            // RT-20643
+            CssError.setCurrentScene(scene);
+
+            platformUserAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
+
+            if (ua_stylesheet != null) {
+                ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+            }
+            userAgentStylesheetsChanged();
+
+            // RT-20643
+            CssError.setCurrentScene(null);
         }
-
-        // RT-20643
-        CssError.setCurrentScene(scene);
-
-        platformUserAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
-
-        if (ua_stylesheet != null) {
-            ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-        }
-        userAgentStylesheetsChanged();
-
-        // RT-20643
-        CssError.setCurrentScene(null);
-
     }
 
     /**
@@ -1303,57 +1338,62 @@
         if (fname == null || fname.isEmpty()) {
             return;
         }
-        // RT-20643
 
-        CssError.setCurrentScene(scene);
+        synchronized (styleLock) {
+            // RT-20643
 
-        if(_setDefaultUserAgentStylesheet(fname)) {
-            userAgentStylesheetsChanged();
+            CssError.setCurrentScene(scene);
+
+            if(_setDefaultUserAgentStylesheet(fname)) {
+                userAgentStylesheetsChanged();
+            }
+
+            // RT-20643
+            CssError.setCurrentScene(null);
         }
-
-        // RT-20643
-        CssError.setCurrentScene(null);
     }
 
     // fname is expected to be non null and non empty
     private boolean _setDefaultUserAgentStylesheet(String fname) {
 
-        // if we already have this stylesheet, make sure it is the first element
-        for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
-            StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-            if (fname.equals(container.fname)) {
-                if (n > 0) {
-                    platformUserAgentStylesheetContainers.remove(n);
-                    if (hasDefaultUserAgentStylesheet) {
-                        platformUserAgentStylesheetContainers.set(0, container);
-                    } else {
-                        platformUserAgentStylesheetContainers.add(0, container);
+        synchronized (styleLock) {
+            // if we already have this stylesheet, make sure it is the first element
+            for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
+                StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                if (fname.equals(container.fname)) {
+                    if (n > 0) {
+                        platformUserAgentStylesheetContainers.remove(n);
+                        if (hasDefaultUserAgentStylesheet) {
+                            platformUserAgentStylesheetContainers.set(0, container);
+                        } else {
+                            platformUserAgentStylesheetContainers.add(0, container);
+                        }
                     }
+                    // return true only if platformUserAgentStylesheetContainers was modified
+                    return n > 0;
                 }
-                // return true only if platformUserAgentStylesheetContainers was modified
-                return n > 0;
             }
+
+            final Stylesheet ua_stylesheet = loadStylesheet(fname);
+
+            if (ua_stylesheet == null) return false;
+
+            ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+            final StylesheetContainer sc = new StylesheetContainer(fname, ua_stylesheet);
+
+            if (platformUserAgentStylesheetContainers.size() == 0) {
+                platformUserAgentStylesheetContainers.add(sc);
+            }
+            else if (hasDefaultUserAgentStylesheet) {
+                platformUserAgentStylesheetContainers.set(0,sc);
+            }
+            else {
+                platformUserAgentStylesheetContainers.add(0,sc);
+            }
+            hasDefaultUserAgentStylesheet = true;
+
+            return true;
         }
-
-        final Stylesheet ua_stylesheet = loadStylesheet(fname);
-
-        if (ua_stylesheet == null) return false;
-
-        ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-        final StylesheetContainer sc = new StylesheetContainer(fname, ua_stylesheet);
-
-        if (platformUserAgentStylesheetContainers.size() == 0) {
-            platformUserAgentStylesheetContainers.add(sc);
-        }
-        else if (hasDefaultUserAgentStylesheet) {
-            platformUserAgentStylesheetContainers.set(0,sc);
-        }
-        else {
-            platformUserAgentStylesheetContainers.add(0,sc);
-        }
-        hasDefaultUserAgentStylesheet = true;
-
-        return true;
     }
 
     /**
@@ -1367,25 +1407,27 @@
         if (fname == null || fname.isEmpty()) {
             return;
         }
- 
-        // if we already have this stylesheet, remove it!
-        boolean removed = false;
-        for (int n = platformUserAgentStylesheetContainers.size() - 1; n >= 0; n--) {
-            // don't remove the platform default user agent stylesheet
-            if (fname.equals(Application.getUserAgentStylesheet())) {
-                continue;
+
+        synchronized (styleLock) {
+            // if we already have this stylesheet, remove it!
+            boolean removed = false;
+            for (int n = platformUserAgentStylesheetContainers.size() - 1; n >= 0; n--) {
+                // don't remove the platform default user agent stylesheet
+                if (fname.equals(Application.getUserAgentStylesheet())) {
+                    continue;
+                }
+
+                StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                if (fname.equals(container.fname)) {
+                    platformUserAgentStylesheetContainers.remove(n);
+                    removed = true;
+                }
             }
- 
-            StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-            if (fname.equals(container.fname)) {
-                platformUserAgentStylesheetContainers.remove(n);
-                removed = true;
+
+            if (removed) {
+                userAgentStylesheetsChanged();
             }
         }
- 
-        if (removed) {
-            userAgentStylesheetsChanged();
-        }
     }
 
     /**
@@ -1401,35 +1443,36 @@
         String url = ua_stylesheet.getUrl();
         final String fname = url != null ? url.trim() : "";
 
-        // if we already have this stylesheet, make sure it is the first element
-        for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
-            StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-            if (fname.equals(container.fname)) {
-                if (n > 0) {
-                    platformUserAgentStylesheetContainers.remove(n);
-                    if (hasDefaultUserAgentStylesheet) {
-                        platformUserAgentStylesheetContainers.set(0, container);
-                    } else {
-                        platformUserAgentStylesheetContainers.add(0, container);
+        synchronized (styleLock) {
+            // if we already have this stylesheet, make sure it is the first element
+            for (int n=0, nMax= platformUserAgentStylesheetContainers.size(); n < nMax; n++) {
+                StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                if (fname.equals(container.fname)) {
+                    if (n > 0) {
+                        platformUserAgentStylesheetContainers.remove(n);
+                        if (hasDefaultUserAgentStylesheet) {
+                            platformUserAgentStylesheetContainers.set(0, container);
+                        } else {
+                            platformUserAgentStylesheetContainers.add(0, container);
+                        }
                     }
+                    return;
                 }
-                return;
             }
+
+            StylesheetContainer sc = new StylesheetContainer(fname, ua_stylesheet);
+            if (platformUserAgentStylesheetContainers.size() == 0) {
+                platformUserAgentStylesheetContainers.add(sc);
+            } else if (hasDefaultUserAgentStylesheet) {
+                platformUserAgentStylesheetContainers.set(0,sc);
+            } else {
+                platformUserAgentStylesheetContainers.add(0,sc);
+            }
+            hasDefaultUserAgentStylesheet = true;
+
+            ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+            userAgentStylesheetsChanged();
         }
-
-        StylesheetContainer sc = new StylesheetContainer(fname, ua_stylesheet);
-        if (platformUserAgentStylesheetContainers.size() == 0) {
-            platformUserAgentStylesheetContainers.add(sc);
-        } else if (hasDefaultUserAgentStylesheet) {
-            platformUserAgentStylesheetContainers.set(0,sc);
-        } else {
-            platformUserAgentStylesheetContainers.add(0,sc);
-        }
-        hasDefaultUserAgentStylesheet = true;
-
-        ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-        userAgentStylesheetsChanged();
-
     }
 
     /*
@@ -1437,18 +1480,21 @@
      */
     private void userAgentStylesheetsChanged() {
 
-        for (CacheContainer container : cacheContainerMap.values()) {
-            container.clearCache();
-        }
+        List<Parent> parents = new ArrayList<>();
 
-        StyleConverterImpl.clearCache();
+        synchronized (styleLock) {
+            for (CacheContainer container : cacheContainerMap.values()) {
+                container.clearCache();
+            }
 
-        List<Parent> parents = new ArrayList<>();
-        for (Parent root : cacheContainerMap.keySet()) {
-            if (root == null) {
-                continue;
+            StyleConverterImpl.clearCache();
+
+            for (Parent root : cacheContainerMap.keySet()) {
+                if (root == null) {
+                    continue;
+                }
+                parents.add(root);
             }
-            parents.add(root);
         }
 
         for (Parent root : parents) root.impl_reapplyCSS();
@@ -1456,54 +1502,56 @@
 
     private List<StylesheetContainer> processStylesheets(List<String> stylesheets, Parent parent) {
 
-        final List<StylesheetContainer> list = new ArrayList<StylesheetContainer>();
-        for (int n = 0, nMax = stylesheets.size(); n < nMax; n++) {
-            final String fname = stylesheets.get(n);
+        synchronized (styleLock) {
+            final List<StylesheetContainer> list = new ArrayList<StylesheetContainer>();
+            for (int n = 0, nMax = stylesheets.size(); n < nMax; n++) {
+                final String fname = stylesheets.get(n);
 
-            StylesheetContainer container = null;
-            if (stylesheetContainerMap.containsKey(fname)) {
-                container = stylesheetContainerMap.get(fname);
+                StylesheetContainer container = null;
+                if (stylesheetContainerMap.containsKey(fname)) {
+                    container = stylesheetContainerMap.get(fname);
 
-                if (!list.contains(container)) {
-                    // minor optimization: if existing checksum in byte[0], then don't bother recalculating
-                    if (container.checksumInvalid) {
-                        final byte[] checksum = calculateCheckSum(fname);
-                        if (!Arrays.equals(checksum, container.checksum)) {
-                            removeStylesheetContainer(container);
+                    if (!list.contains(container)) {
+                        // minor optimization: if existing checksum in byte[0], then don't bother recalculating
+                        if (container.checksumInvalid) {
+                            final byte[] checksum = calculateCheckSum(fname);
+                            if (!Arrays.equals(checksum, container.checksum)) {
+                                removeStylesheetContainer(container);
 
-                            // Stylesheet did change. Re-load the stylesheet and update the container map.
-                            Stylesheet stylesheet = loadStylesheet(fname);
-                            container = new StylesheetContainer(fname, stylesheet, checksum);
-                            stylesheetContainerMap.put(fname, container);
-                        } else {
-                            container.checksumInvalid = false;
+                                // Stylesheet did change. Re-load the stylesheet and update the container map.
+                                Stylesheet stylesheet = loadStylesheet(fname);
+                                container = new StylesheetContainer(fname, stylesheet, checksum);
+                                stylesheetContainerMap.put(fname, container);
+                            } else {
+                                container.checksumInvalid = false;
+                            }
                         }
+                        list.add(container);
                     }
+
+                    // RT-22565: remember that this parent or scene uses this stylesheet.
+                    // Later, if the cache is cleared, the parent or scene is told to
+                    // reapply css.
+                    container.parentUsers.add(parent);
+
+                } else {
+                    final Stylesheet stylesheet = loadStylesheet(fname);
+                    // stylesheet may be null which would mean that some IOException
+                    // was thrown while trying to load it. Add it to the
+                    // stylesheetContainerMap anyway as this will prevent further
+                    // attempts to parse the file
+                    container = new StylesheetContainer(fname, stylesheet);
+                    // RT-22565: remember that this parent or scene uses this stylesheet.
+                    // Later, if the cache is cleared, the parent or scene is told to
+                    // reapply css.
+                    container.parentUsers.add(parent);
+                    stylesheetContainerMap.put(fname, container);
+
                     list.add(container);
                 }
-
-                // RT-22565: remember that this parent or scene uses this stylesheet.
-                // Later, if the cache is cleared, the parent or scene is told to
-                // reapply css.
-                container.parentUsers.add(parent);
-
-            } else {
-                final Stylesheet stylesheet = loadStylesheet(fname);
-                // stylesheet may be null which would mean that some IOException
-                // was thrown while trying to load it. Add it to the
-                // stylesheetContainerMap anyway as this will prevent further
-                // attempts to parse the file
-                container = new StylesheetContainer(fname, stylesheet);
-                // RT-22565: remember that this parent or scene uses this stylesheet.
-                // Later, if the cache is cleared, the parent or scene is told to
-                // reapply css.
-                container.parentUsers.add(parent);
-                stylesheetContainerMap.put(fname, container);
-
-                list.add(container);
             }
+            return list;
         }
-        return list;
     }
 
     //
@@ -1524,15 +1572,17 @@
             return Collections.<StylesheetContainer>emptyList();
         }
 
-        // RT-20643
-        CssError.setCurrentScene(parent.getScene());
+        synchronized (styleLock) {
+            // RT-20643
+            CssError.setCurrentScene(parent.getScene());
 
-        final List<StylesheetContainer> list = processStylesheets(parentStylesheets, parent);
+            final List<StylesheetContainer> list = processStylesheets(parentStylesheets, parent);
 
-        // RT-20643
-        CssError.setCurrentScene(null);
+            // RT-20643
+            CssError.setCurrentScene(null);
 
-        return list;
+            return list;
+        }
     }
 
     //
@@ -1550,15 +1600,17 @@
             return Collections.<StylesheetContainer>emptyList();
         }
 
-        // RT-20643
-        CssError.setCurrentScene(scene);
+        synchronized (styleLock) {
+            // RT-20643
+            CssError.setCurrentScene(scene);
 
-        final List<StylesheetContainer> list = processStylesheets(sceneStylesheets, scene.getRoot());
+            final List<StylesheetContainer> list = processStylesheets(sceneStylesheets, scene.getRoot());
 
-        // RT-20643
-        CssError.setCurrentScene(null);
+            // RT-20643
+            CssError.setCurrentScene(null);
 
-        return list;
+            return list;
+        }
     }
 
     // reuse key to avoid creation of numerous small objects
@@ -1580,216 +1632,218 @@
             return StyleMap.EMPTY_MAP;
         }
 
-        final Parent parent =
-            (node instanceof Parent)
-                ? (Parent) node : node.getParent();
+        synchronized (styleLock) {
+            final Parent parent =
+                (node instanceof Parent)
+                    ? (Parent) node : node.getParent();
 
-        final List<StylesheetContainer> parentStylesheets =
-                    gatherParentStylesheets(parent);
+            final List<StylesheetContainer> parentStylesheets =
+                        gatherParentStylesheets(parent);
 
-        final boolean hasParentStylesheets = parentStylesheets.isEmpty() == false;
+            final boolean hasParentStylesheets = parentStylesheets.isEmpty() == false;
 
-        final List<StylesheetContainer> sceneStylesheets = gatherSceneStylesheets(scene);
+            final List<StylesheetContainer> sceneStylesheets = gatherSceneStylesheets(scene);
 
-        final boolean hasSceneStylesheets = sceneStylesheets.isEmpty() == false;
+            final boolean hasSceneStylesheets = sceneStylesheets.isEmpty() == false;
 
-        final String inlineStyle = node.getStyle();
-        final boolean hasInlineStyles = inlineStyle != null && inlineStyle.trim().isEmpty() == false;
+            final String inlineStyle = node.getStyle();
+            final boolean hasInlineStyles = inlineStyle != null && inlineStyle.trim().isEmpty() == false;
 
-        final String sceneUserAgentStylesheet = scene.getUserAgentStylesheet();
-        final boolean hasSceneUserAgentStylesheet =
-                sceneUserAgentStylesheet != null && sceneUserAgentStylesheet.trim().isEmpty() == false;
+            final String sceneUserAgentStylesheet = scene.getUserAgentStylesheet();
+            final boolean hasSceneUserAgentStylesheet =
+                    sceneUserAgentStylesheet != null && sceneUserAgentStylesheet.trim().isEmpty() == false;
 
-        final String subSceneUserAgentStylesheet =
-                (subScene != null) ? subScene.getUserAgentStylesheet() : null;
-        final boolean hasSubSceneUserAgentStylesheet =
-                subSceneUserAgentStylesheet != null && subSceneUserAgentStylesheet.trim().isEmpty() == false;
+            final String subSceneUserAgentStylesheet =
+                    (subScene != null) ? subScene.getUserAgentStylesheet() : null;
+            final boolean hasSubSceneUserAgentStylesheet =
+                    subSceneUserAgentStylesheet != null && subSceneUserAgentStylesheet.trim().isEmpty() == false;
 
-        String regionUserAgentStylesheet = null;
-        // is this node in a region that has its own stylesheet?
-        Node region = node;
-        while (region != null) {
-            regionUserAgentStylesheet = (region instanceof Region) ? ((Region) region).getUserAgentStylesheet() : null;
-            if (regionUserAgentStylesheet != null) {
-                // We want 'region' to be the node that has the user agent stylesheet.
-                // 'region' is used below - look for if (hasRegionUserAgentStylesheet) block
-                break;
+            String regionUserAgentStylesheet = null;
+            // is this node in a region that has its own stylesheet?
+            Node region = node;
+            while (region != null) {
+                regionUserAgentStylesheet = (region instanceof Region) ? ((Region) region).getUserAgentStylesheet() : null;
+                if (regionUserAgentStylesheet != null) {
+                    // We want 'region' to be the node that has the user agent stylesheet.
+                    // 'region' is used below - look for if (hasRegionUserAgentStylesheet) block
+                    break;
+                }
+                region = region.getParent();
             }
-            region = region.getParent();
-        }
 
 
-        final boolean hasRegionUserAgentStylesheet =
-                regionUserAgentStylesheet != null && regionUserAgentStylesheet.trim().isEmpty() == false;
+            final boolean hasRegionUserAgentStylesheet =
+                    regionUserAgentStylesheet != null && regionUserAgentStylesheet.trim().isEmpty() == false;
 
-        //
-        // Are there any stylesheets at all?
-        // If not, then there is nothing to match and the
-        // resulting StyleMap is going to end up empty
-        //
-        if (hasInlineStyles == false
-                && hasParentStylesheets == false
-                && hasSceneStylesheets == false
-                && hasSceneUserAgentStylesheet == false
-                && hasSubSceneUserAgentStylesheet == false
-                && hasRegionUserAgentStylesheet == false
-                && platformUserAgentStylesheetContainers.isEmpty()) {
-            return StyleMap.EMPTY_MAP;
-        }
+            //
+            // Are there any stylesheets at all?
+            // If not, then there is nothing to match and the
+            // resulting StyleMap is going to end up empty
+            //
+            if (hasInlineStyles == false
+                    && hasParentStylesheets == false
+                    && hasSceneStylesheets == false
+                    && hasSceneUserAgentStylesheet == false
+                    && hasSubSceneUserAgentStylesheet == false
+                    && hasRegionUserAgentStylesheet == false
+                    && platformUserAgentStylesheetContainers.isEmpty()) {
+                return StyleMap.EMPTY_MAP;
+            }
 
-        final String cname = node.getTypeSelector();
-        final String id = node.getId();
-        final List<String> styleClasses = node.getStyleClass();
+            final String cname = node.getTypeSelector();
+            final String id = node.getId();
+            final List<String> styleClasses = node.getStyleClass();
 
-        if (key == null) {
-            key = new Key();
-        }
+            if (key == null) {
+                key = new Key();
+            }
 
-        key.className = cname;
-        key.id = id;
-        for(int n=0, nMax=styleClasses.size(); n<nMax; n++) {
+            key.className = cname;
+            key.id = id;
+            for(int n=0, nMax=styleClasses.size(); n<nMax; n++) {
 
-            final String styleClass = styleClasses.get(n);
-            if (styleClass == null || styleClass.isEmpty()) continue;
+                final String styleClass = styleClasses.get(n);
+                if (styleClass == null || styleClass.isEmpty()) continue;
 
-            key.styleClasses.add(StyleClassSet.getStyleClass(styleClass));
-        }
+                key.styleClasses.add(StyleClassSet.getStyleClass(styleClass));
+            }
 
-        Map<Key, Cache> cacheMap = cacheContainer.getCacheMap(parentStylesheets,regionUserAgentStylesheet);
-        Cache cache = cacheMap.get(key);
+            Map<Key, Cache> cacheMap = cacheContainer.getCacheMap(parentStylesheets,regionUserAgentStylesheet);
+            Cache cache = cacheMap.get(key);
 
-        if (cache != null) {
-            // key will be reused, so clear the styleClasses for next use
-            key.styleClasses.clear();
+            if (cache != null) {
+                // key will be reused, so clear the styleClasses for next use
+                key.styleClasses.clear();
 
-        } else {
+            } else {
 
-            // If the cache is null, then we need to create a new Cache and
-            // add it to the cache map
+                // If the cache is null, then we need to create a new Cache and
+                // add it to the cache map
 
-            // Construct the list of Selectors that could possibly apply
-            final List<Selector> selectorData = new ArrayList<>();
+                // Construct the list of Selectors that could possibly apply
+                final List<Selector> selectorData = new ArrayList<>();
 
-            // User agent stylesheets have lowest precedence and go first
-            if (hasSubSceneUserAgentStylesheet || hasSceneUserAgentStylesheet) {
+                // User agent stylesheets have lowest precedence and go first
+                if (hasSubSceneUserAgentStylesheet || hasSceneUserAgentStylesheet) {
 
-                // if has both, use SubScene
-                final String uaFileName = hasSubSceneUserAgentStylesheet ?
-                        subScene.getUserAgentStylesheet().trim() :
-                        scene.getUserAgentStylesheet().trim();
+                    // if has both, use SubScene
+                    final String uaFileName = hasSubSceneUserAgentStylesheet ?
+                            subScene.getUserAgentStylesheet().trim() :
+                            scene.getUserAgentStylesheet().trim();
 
 
-                StylesheetContainer container = null;
-                for (int n=0, nMax=userAgentStylesheetContainers.size(); n<nMax; n++) {
-                    container = userAgentStylesheetContainers.get(n);
-                    if (uaFileName.equals(container.fname)) {
-                        break;
+                    StylesheetContainer container = null;
+                    for (int n=0, nMax=userAgentStylesheetContainers.size(); n<nMax; n++) {
+                        container = userAgentStylesheetContainers.get(n);
+                        if (uaFileName.equals(container.fname)) {
+                            break;
+                        }
+                        container = null;
                     }
-                    container = null;
-                }
 
-                if (container == null) {
-                    Stylesheet stylesheet = loadStylesheet(uaFileName);
-                    if (stylesheet != null) {
-                        stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+                    if (container == null) {
+                        Stylesheet stylesheet = loadStylesheet(uaFileName);
+                        if (stylesheet != null) {
+                            stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+                        }
+                        container = new StylesheetContainer(uaFileName, stylesheet);
+                        userAgentStylesheetContainers.add(container);
                     }
-                    container = new StylesheetContainer(uaFileName, stylesheet);
-                    userAgentStylesheetContainers.add(container);
-                }
 
-                if (container.selectorPartitioning != null) {
+                    if (container.selectorPartitioning != null) {
 
-                    final Parent root = hasSubSceneUserAgentStylesheet ? subScene.getRoot() : scene.getRoot();
-                    container.parentUsers.add(root);
+                        final Parent root = hasSubSceneUserAgentStylesheet ? subScene.getRoot() : scene.getRoot();
+                        container.parentUsers.add(root);
 
-                    final List<Selector> matchingRules =
-                            container.selectorPartitioning.match(id, cname, key.styleClasses);
-                    selectorData.addAll(matchingRules);
-                }
-
-            } else if (platformUserAgentStylesheetContainers.isEmpty() == false) {
-                for(int n=0, nMax= platformUserAgentStylesheetContainers.size(); n<nMax; n++) {
-                    final StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
-                    if (container != null && container.selectorPartitioning != null) {
                         final List<Selector> matchingRules =
                                 container.selectorPartitioning.match(id, cname, key.styleClasses);
                         selectorData.addAll(matchingRules);
                     }
-                }
-            }
 
-            if (hasRegionUserAgentStylesheet) {
-                // Unfortunate duplication of code from previous block. No time to refactor.
-                StylesheetContainer container = null;
-                for (int n=0, nMax=userAgentStylesheetContainers.size(); n<nMax; n++) {
-                    container = userAgentStylesheetContainers.get(n);
-                    if (regionUserAgentStylesheet.equals(container.fname)) {
-                        break;
+                } else if (platformUserAgentStylesheetContainers.isEmpty() == false) {
+                    for(int n=0, nMax= platformUserAgentStylesheetContainers.size(); n<nMax; n++) {
+                        final StylesheetContainer container = platformUserAgentStylesheetContainers.get(n);
+                        if (container != null && container.selectorPartitioning != null) {
+                            final List<Selector> matchingRules =
+                                    container.selectorPartitioning.match(id, cname, key.styleClasses);
+                            selectorData.addAll(matchingRules);
+                        }
                     }
-                    container = null;
                 }
 
-                if (container == null) {
-                    Stylesheet stylesheet = loadStylesheet(regionUserAgentStylesheet);
-                    if (stylesheet != null) {
-                        stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+                if (hasRegionUserAgentStylesheet) {
+                    // Unfortunate duplication of code from previous block. No time to refactor.
+                    StylesheetContainer container = null;
+                    for (int n=0, nMax=userAgentStylesheetContainers.size(); n<nMax; n++) {
+                        container = userAgentStylesheetContainers.get(n);
+                        if (regionUserAgentStylesheet.equals(container.fname)) {
+                            break;
+                        }
+                        container = null;
                     }
-                    container = new StylesheetContainer(regionUserAgentStylesheet, stylesheet);
-                    userAgentStylesheetContainers.add(container);
-                }
 
-                if (container.selectorPartitioning != null) {
+                    if (container == null) {
+                        Stylesheet stylesheet = loadStylesheet(regionUserAgentStylesheet);
+                        if (stylesheet != null) {
+                            stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+                        }
+                        container = new StylesheetContainer(regionUserAgentStylesheet, stylesheet);
+                        userAgentStylesheetContainers.add(container);
+                    }
 
-                    // Depending on RefList add method not allowing duplicates.
-                    container.parentUsers.add((Parent)region);
+                    if (container.selectorPartitioning != null) {
 
-                    final List<Selector> matchingRules =
-                            container.selectorPartitioning.match(id, cname, key.styleClasses);
-                    selectorData.addAll(matchingRules);
-                }
+                        // Depending on RefList add method not allowing duplicates.
+                        container.parentUsers.add((Parent)region);
 
-            }
-
-            // Scene stylesheets come next since declarations from
-            // parent stylesheets should take precedence.
-            if (sceneStylesheets.isEmpty() == false) {
-                for(int n=0, nMax=sceneStylesheets.size(); n<nMax; n++) {
-                    final StylesheetContainer container = sceneStylesheets.get(n);
-                    if (container != null && container.selectorPartitioning != null) {
                         final List<Selector> matchingRules =
                                 container.selectorPartitioning.match(id, cname, key.styleClasses);
                         selectorData.addAll(matchingRules);
                     }
+
                 }
+
+                // Scene stylesheets come next since declarations from
+                // parent stylesheets should take precedence.
+                if (sceneStylesheets.isEmpty() == false) {
+                    for(int n=0, nMax=sceneStylesheets.size(); n<nMax; n++) {
+                        final StylesheetContainer container = sceneStylesheets.get(n);
+                        if (container != null && container.selectorPartitioning != null) {
+                            final List<Selector> matchingRules =
+                                    container.selectorPartitioning.match(id, cname, key.styleClasses);
+                            selectorData.addAll(matchingRules);
+                        }
+                    }
+                }
+
+                // lastly, parent stylesheets
+                if (hasParentStylesheets) {
+                    final int nMax = parentStylesheets == null ? 0 : parentStylesheets.size();
+                    for(int n=0; n<nMax; n++) {
+                        final StylesheetContainer container = parentStylesheets.get(n);
+                        if (container.selectorPartitioning != null) {
+                            final List<Selector> matchingRules =
+                                    container.selectorPartitioning.match(id, cname, key.styleClasses);
+                            selectorData.addAll(matchingRules);
+                        }
+                    }
+                }
+
+                // create a new Cache from these selectors.
+                cache = new Cache(selectorData);
+                cacheMap.put(key, cache);
+
+                // cause a new Key to be created the next time this method is called
+                key = null;
             }
 
-            // lastly, parent stylesheets
-            if (hasParentStylesheets) {
-                final int nMax = parentStylesheets == null ? 0 : parentStylesheets.size();
-                for(int n=0; n<nMax; n++) {
-                    final StylesheetContainer container = parentStylesheets.get(n);
-                    if (container.selectorPartitioning != null) {
-                        final List<Selector> matchingRules =
-                                container.selectorPartitioning.match(id, cname, key.styleClasses);
-                        selectorData.addAll(matchingRules);
-                    }
-                }
-            }
+            //
+            // Create a style helper for this node from the styles that match.
+            //
+            StyleMap smap = cache.getStyleMap(cacheContainer, node, triggerStates, hasInlineStyles);
 
-            // create a new Cache from these selectors.
-            cache = new Cache(selectorData);
-            cacheMap.put(key, cache);
-
-            // cause a new Key to be created the next time this method is called
-            key = null;
+            return smap;
         }
-
-        //
-        // Create a style helper for this node from the styles that match.
-        //
-        StyleMap smap = cache.getStyleMap(cacheContainer, node, triggerStates, hasInlineStyles);
-
-        return smap;
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -1802,6 +1856,12 @@
     /**
      * Errors that may have occurred during css processing.
      * This list is null until errorsProperty() is called.
+     *
+     * NOTE: this is not thread-safe, and cannot readily be made so given the
+     * nature of the API.
+     * Currently it is only used by SceneBuilder. If a public API is ever
+     * needed, then a new API should be designed.
+     *
      * @return
      */
     public static ObservableList<CssError> errorsProperty() {
@@ -1846,42 +1906,44 @@
                 cacheMap = new HashMap<List<String>,Map<Key,Cache>>();
             }
 
-            if ((parentStylesheets == null || parentStylesheets.isEmpty()) &&
-                    (regionUserAgentStylesheet == null || regionUserAgentStylesheet.isEmpty())) {
+            synchronized (styleLock) {
+                if ((parentStylesheets == null || parentStylesheets.isEmpty()) &&
+                        (regionUserAgentStylesheet == null || regionUserAgentStylesheet.isEmpty())) {
 
-                Map<Key,Cache> cmap = cacheMap.get(null);
-                if (cmap == null) {
-                    cmap = new HashMap<Key,Cache>();
-                    cacheMap.put(null, cmap);
+                    Map<Key,Cache> cmap = cacheMap.get(null);
+                    if (cmap == null) {
+                        cmap = new HashMap<Key,Cache>();
+                        cacheMap.put(null, cmap);
+                    }
+                    return cmap;
+
+                } else {
+
+                    final int nMax = parentStylesheets.size();
+                    if (cacheMapKey == null) {
+                        cacheMapKey = new ArrayList<String>(nMax);
+                    }
+                    for (int n=0; n<nMax; n++) {
+                        StylesheetContainer sc = parentStylesheets.get(n);
+                        if (sc == null || sc.fname == null || sc.fname.isEmpty()) continue;
+                        cacheMapKey.add(sc.fname);
+                    }
+                    if (regionUserAgentStylesheet != null) {
+                        cacheMapKey.add(regionUserAgentStylesheet);
+                    }
+                    Map<Key,Cache> cmap = cacheMap.get(cacheMapKey);
+                    if (cmap == null) {
+                        cmap = new HashMap<Key,Cache>();
+                        cacheMap.put(cacheMapKey, cmap);
+                        // create a new cacheMapKey the next time this method is called
+                        cacheMapKey = null;
+                    } else {
+                        // reuse cacheMapKey, but not the data, the next time this method is called
+                        cacheMapKey.clear();
+                    }
+                    return cmap;
+
                 }
-                return cmap;
-
-            } else {
-
-                final int nMax = parentStylesheets.size();
-                if (cacheMapKey == null) {
-                    cacheMapKey = new ArrayList<String>(nMax);
-                }
-                for (int n=0; n<nMax; n++) {
-                    StylesheetContainer sc = parentStylesheets.get(n);
-                    if (sc == null || sc.fname == null || sc.fname.isEmpty()) continue;
-                    cacheMapKey.add(sc.fname);
-                }
-                if (regionUserAgentStylesheet != null) {
-                    cacheMapKey.add(regionUserAgentStylesheet);
-                }
-                Map<Key,Cache> cmap = cacheMap.get(cacheMapKey);
-                if (cmap == null) {
-                    cmap = new HashMap<Key,Cache>();
-                    cacheMap.put(cacheMapKey, cmap);
-                    // create a new cacheMapKey the next time this method is called
-                    cacheMapKey = null;
-                } else {
-                    // reuse cacheMapKey, but not the data, the next time this method is called
-                    cacheMapKey.clear();
-                }
-                return cmap;
-
             }
 
         }
@@ -1946,7 +2008,7 @@
             }
 
             final Stylesheet inlineStylesheet =
-                    CSSParser.getInstance().parse("*{"+inlineStyle+"}");
+                    new CSSParser().parse("*{"+inlineStyle+"}");
 
             if (inlineStylesheet != null) {
 
@@ -2001,7 +2063,7 @@
         // cache and is no longer valid.
         private int baseStyleMapId = 0;
 
-            }
+    }
 
     /**
      * Creates and caches maps of styles, reusing them as often as practical.
--- a/modules/graphics/src/main/java/com/sun/javafx/css/Stylesheet.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/css/Stylesheet.java	Fri Jun 05 17:39:54 2015 -0700
@@ -310,7 +310,7 @@
         }
 
         URI sourceURI = source.toURI();
-        Stylesheet stylesheet = CSSParser.getInstance().parse(sourceURI.toURL());
+        Stylesheet stylesheet = new CSSParser().parse(sourceURI.toURL());
 
         // first write all the css binary data into the buffer and collect strings on way
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
--- a/modules/graphics/src/main/java/com/sun/javafx/css/parser/CSSParser.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/css/parser/CSSParser.java	Fri Jun 05 17:39:54 2015 -0700
@@ -114,17 +114,12 @@
 
 final public class CSSParser {
 
-    /* Lazy instantiation */
-    private static class InstanceHolder {
-        final static CSSParser INSTANCE = new CSSParser();
-    }
-
     /**
      * @deprecated As of 8u40, use new CSSParser() instead.
      */
     @Deprecated
     public static CSSParser getInstance() {
-        return InstanceHolder.INSTANCE;
+        return new CSSParser();
     }
 
     public CSSParser() {
--- a/modules/graphics/src/main/java/com/sun/javafx/iio/bmp/BMPImageLoaderFactory.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/iio/bmp/BMPImageLoaderFactory.java	Fri Jun 05 17:39:54 2015 -0700
@@ -474,19 +474,18 @@
 
         int hght = Math.abs(bih.biHeight);
 
-        if ((width > 0 && width != bih.biWidth) ||
-            (height > 0 && height != hght))
-        {
-            throw new IOException("scaling for BMP is not supported");
-        }
+        int[] outWH = ImageTools.computeDimensions(bih.biWidth, hght, width, height, preserveAspectRatio);
+        width = outWH[0];
+        height = outWH[1];
 
         // Pass image metadata to any listeners.
         ImageMetadata imageMetadata = new ImageMetadata(null, Boolean.TRUE,
-            null, null, null, null, null, bih.biWidth, hght,
+            null, null, null, null, null, width, height,
             null, null, null);
         updateImageMetadata(imageMetadata);
 
-        int stride = bih.biWidth * 3;
+        int bpp = 3;
+        int stride = bih.biWidth * bpp;
 
         byte image[] = new byte[stride * hght];
 
@@ -529,8 +528,14 @@
                 throw new IOException("Unknown BMP bit depth");
         }
 
-        return new ImageFrame(ImageStorage.ImageType.RGB, ByteBuffer.wrap(image),
-                bih.biWidth, hght, stride, null, null);
+        ByteBuffer img = ByteBuffer.wrap(image);
+        if (bih.biWidth != width || hght != height) {
+            img = ImageTools.scaleImage(img, bih.biWidth, hght, bpp,
+                    width, height, smooth);
+        }
+
+        return new ImageFrame(ImageStorage.ImageType.RGB, img,
+                width, height, width * bpp, null, imageMetadata);
     }
 }
 
--- a/modules/graphics/src/main/java/com/sun/javafx/iio/common/ImageTools.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/iio/common/ImageTools.java	Fri Jun 05 17:39:54 2015 -0700
@@ -29,6 +29,7 @@
 import com.sun.javafx.geom.Rectangle;
 import com.sun.javafx.iio.ImageFrame;
 import com.sun.javafx.iio.ImageMetadata;
+import com.sun.javafx.iio.ImageStorage;
 import com.sun.javafx.iio.ImageStorage.ImageType;
 import java.io.EOFException;
 import java.io.File;
@@ -692,6 +693,42 @@
 
         return new int[]{finalWidth, finalHeight};
     }
+    
+    public static ImageFrame scaleImageFrame(ImageFrame src,
+            int destWidth, int destHeight, boolean isSmooth)
+    {
+        int numBands = ImageStorage.getNumBands(src.getImageType());
+        ByteBuffer dst = scaleImage((ByteBuffer) src.getImageData(),
+                src.getWidth(), src.getHeight(), numBands,
+                destWidth, destHeight, isSmooth);
+        return new ImageFrame(src.getImageType(), dst,
+                destWidth, destHeight, destWidth * numBands, null, src.getMetadata());
+    }
+
+    public static ByteBuffer scaleImage(ByteBuffer src,
+            int sourceWidth, int sourceHeight, int numBands,
+            int destWidth, int destHeight, boolean isSmooth)
+    {
+        PushbroomScaler scaler = ScalerFactory.createScaler(
+                sourceWidth, sourceHeight, numBands,
+                destWidth, destHeight, isSmooth);
+
+        int stride = sourceWidth * numBands;
+        if (src.hasArray()) {
+            byte image[] = src.array();
+            for (int y = 0; y != sourceHeight; ++y) {
+                scaler.putSourceScanline(image, y * stride);
+            }
+        } else {
+            byte scanline[] = new byte[stride];
+            for (int y = 0; y != sourceHeight; ++y) {
+                src.get(scanline);
+                scaler.putSourceScanline(scanline, 0);
+            }
+        }
+
+        return scaler.getDestination();
+    }    
 //    public static final java.awt.image.BufferedImage getAsBufferedImage(Image prismImage) {
 //        java.awt.image.BufferedImage image = null;
 //
--- a/modules/graphics/src/main/java/com/sun/javafx/iio/gif/GIFImageLoader2.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/iio/gif/GIFImageLoader2.java	Fri Jun 05 17:39:54 2015 -0700
@@ -30,8 +30,6 @@
 import com.sun.javafx.iio.ImageStorage;
 import com.sun.javafx.iio.common.ImageLoaderImpl;
 import com.sun.javafx.iio.common.ImageTools;
-import com.sun.javafx.iio.common.PushbroomScaler;
-import com.sun.javafx.iio.common.ScalerFactory;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -223,23 +221,26 @@
 
         byte palette[][] = localPalette ? readPalete(2 << (imgCtrl & 7), trnsIndex) : globalPalette;
 
-        ImageMetadata metadata = updateMetadata(screenW, screenH, imageControlCode & 0xFFFF);
+        int[] outWH = ImageTools.computeDimensions(screenW, screenH, width, height, preserveAspectRatio);
+        width = outWH[0];
+        height = outWH[1];
+
+        ImageMetadata metadata = updateMetadata(width, height, imageControlCode & 0xFFFF);
 
         int disposalCode = (imageControlCode >>> 26) & 7;
         byte pImage[] = new byte[w * h];
         decodeImage(pImage, w, h, isInterlaced ? computeInterlaceReIndex(h) : null);
 
-        ImageFrame imgGIF = decodePalette(pImage, palette, trnsIndex,
-                left, top, w, h, disposalCode, metadata);
+        ByteBuffer img = decodePalette(pImage, palette, trnsIndex,
+                left, top, w, h, disposalCode);
 
-        // need to remove scaler from image decoder itself
-        int[] outWH = ImageTools.computeDimensions(screenW, screenH, width, height, preserveAspectRatio);
-
-        if (screenW != outWH[0] || screenH != outWH[1]) {
-            imgGIF = scaleImage(imgGIF, outWH[0], outWH[1], smooth);
+        if (screenW != width || screenH != height) {
+            img = ImageTools.scaleImage(img, screenW, screenH, 4,
+                    width, height, smooth);
         }
 
-        return imgGIF;
+        return new ImageFrame(ImageStorage.ImageType.RGBA, img,
+                width, height, width * 4, null, metadata);
     }
 
     // IO helpers
@@ -290,8 +291,8 @@
     }
 
     // decode palletized image into RGBA
-    private ImageFrame decodePalette(byte[] srcImage, byte[][] palette, int trnsIndex,
-            int left, int top, int w, int h, int disposalCode, ImageMetadata metadata) {
+    private ByteBuffer decodePalette(byte[] srcImage, byte[][] palette, int trnsIndex,
+            int left, int top, int w, int h, int disposalCode) {
 
         byte img[] = (disposalCode == 3) ? image.clone() : image;
 
@@ -322,25 +323,7 @@
         if (disposalCode != 3) img = img.clone();
         if (disposalCode == 2) restoreToBackground(image, left, top, w, h);
 
-        return new ImageFrame(ImageStorage.ImageType.RGBA, ByteBuffer.wrap(img),
-                screenW, screenH, screenW * 4, null, metadata);
-    }
-
-    // copy from PNG, needs exctract refactoring later
-    // scales the image
-    private ImageFrame scaleImage(ImageFrame imgPNG, int rWidth, int rHeight, boolean smooth) {
-        byte image[] = ((ByteBuffer) imgPNG.getImageData()).array();
-        int bpp = ImageStorage.getNumBands(imgPNG.getImageType());
-
-        PushbroomScaler scaler = ScalerFactory.createScaler(screenW, screenH, bpp,
-                rWidth, rHeight, smooth);
-
-        for (int y = 0; y != screenH; ++y) {
-            scaler.putSourceScanline(image, y * screenW * bpp);
-        }
-
-        return new ImageFrame(imgPNG.getImageType(), scaler.getDestination(),
-                rWidth, rHeight, rWidth * bpp, null, imgPNG.getMetadata());
+        return ByteBuffer.wrap(img);
     }
 
     // fill metadata
--- a/modules/graphics/src/main/java/com/sun/javafx/iio/ios/IosImageLoader.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/iio/ios/IosImageLoader.java	Fri Jun 05 17:39:54 2015 -0700
@@ -240,8 +240,8 @@
                 null, // a palette index to be used as transparency
                 delayTime == 0 ? null : delayTime, // the amount of time to pause at the current image (milliseconds).
                 nImages > 1 ? loopCount : null, // number of loops
-                inWidth, // source width
-                inHeight, // source height
+                width, // image width
+                height, // image height
                 null, // image left offset
                 null, // image top offset
                 null); // disposal method
--- a/modules/graphics/src/main/java/com/sun/javafx/iio/jpeg/JPEGImageLoader.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/iio/jpeg/JPEGImageLoader.java	Fri Jun 05 17:39:54 2015 -0700
@@ -31,8 +31,6 @@
 import com.sun.glass.utils.NativeLibLoader;
 import com.sun.javafx.iio.common.ImageLoaderImpl;
 import com.sun.javafx.iio.common.ImageTools;
-import com.sun.javafx.iio.common.PushbroomScaler;
-import com.sun.javafx.iio.common.ScalerFactory;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
@@ -223,7 +221,7 @@
 
         ImageMetadata md = new ImageMetadata(null, true,
                 null, null, null, null, null,
-                inWidth, inHeight, null, null, null);
+                width, height, null, null, null);
 
         updateImageMetadata(md);
 
@@ -251,45 +249,18 @@
             throw new IOException("Error decompressing JPEG stream!");
         }
 
-        ImageFrame frame = null;
-
         // Check whether the decompressed image has been scaled to the correct
-        // dimensions. If not, downscalte it here. Note outData, outHeight, and
+        // dimensions. If not, downscale it here. Note outData, outHeight, and
         // outWidth refer to the image as returned by the decompressor. This
         // image might have been downscaled from the original source by a factor
         // of N/8 where 1 <= N <=8.
         if (outWidth != width || outHeight != height) {
-            // Get the decompressed data array. Note that the code really should
-            // be moidified to use direct buffers if and only if this post-
-            // decompression scaling will NOT occur.
-            byte[] outData;
-            if (buffer.hasArray()) {
-                outData = buffer.array();
-            } else {
-                outData = new byte[buffer.capacity()];
-                buffer.get(outData);
-            }
-
-            PushbroomScaler scaler = ScalerFactory.createScaler(outWidth, outHeight,
-                    outNumComponents, width, height, smooth);
-            int stride = outWidth * outNumComponents;
-            int off = 0;
-            for (int y = 0; y < outHeight; y++) {
-                if (scaler.putSourceScanline(outData, off)) {
-                    break;
-                }
-                off += stride;
-            }
-            buffer = scaler.getDestination();
-            frame = new ImageFrame(outImageType, buffer,
-                    width, height, width * outNumComponents, null, md);
-        }
-        else {
-            frame = new ImageFrame(outImageType, buffer,
-                                   outWidth, outHeight, outWidth * outNumComponents, null, md);
+            buffer = ImageTools.scaleImage(buffer,
+                    outWidth, outHeight, outNumComponents, width, height, smooth);
         }
 
-        return frame;
+        return new ImageFrame(outImageType, buffer,
+                width, height, width * outNumComponents, null, md);
     }
 
     private static class Lock {
--- a/modules/graphics/src/main/java/com/sun/javafx/iio/png/PNGImageLoader2.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/iio/png/PNGImageLoader2.java	Fri Jun 05 17:39:54 2015 -0700
@@ -295,13 +295,6 @@
     public void dispose() {
     }
 
-    private ImageMetadata updateMetadata() {
-        ImageMetadata metaData = new ImageMetadata(null, true,
-                null, null, null, null, null, width, height, null, null, null);
-        updateImageMetadata(metaData);
-        return metaData;
-    }
-
     private ImageStorage.ImageType getType() {
         switch (colorType) {
             case PNG_COLOR_GRAY:
@@ -647,9 +640,16 @@
             return null;
         }
 
+        int[] outWH = ImageTools.computeDimensions(width, height, rWidth, rHeight, preserveAspectRatio);
+        rWidth = outWH[0];
+        rHeight = outWH[1];
+        
+        ImageMetadata metaData = new ImageMetadata(null, true,
+                null, null, null, null, null, rWidth, rHeight, null, null, null);
+        updateImageMetadata(metaData);
+
         int bpp = bpp();
         ByteBuffer bb = ByteBuffer.allocate(bpp * width * height);
-        ImageMetadata metadata = updateMetadata();
 
         PNGIDATChunkInputStream iDat = new PNGIDATChunkInputStream(stream, dataSize);
         Inflater inf = new Inflater();
@@ -666,31 +666,13 @@
         }
 
         ImageFrame imgPNG = colorType == PNG_COLOR_PALETTE
-                ? decodePalette(bb.array(), metadata)
-                : new ImageFrame(getType(), bb, width, height, bpp * width, palette, metadata);
+                ? decodePalette(bb.array(), metaData)
+                : new ImageFrame(getType(), bb, width, height, bpp * width, palette, metaData);
 
-        // need remove scaler form loader
-        int[] outWH = ImageTools.computeDimensions(width, height, rWidth, rHeight, preserveAspectRatio);
-
-        if (width != outWH[0] || height != outWH[1]) {
-            imgPNG = scaleImage(imgPNG, outWH[0], outWH[1], smooth);
+        if (width != rWidth || height != rHeight) {
+            imgPNG = ImageTools.scaleImageFrame(imgPNG, rWidth, rHeight, smooth);
         }
 
         return imgPNG;
     }
-
-    private ImageFrame scaleImage(ImageFrame imgPNG, int rWidth, int rHeight, boolean smooth) {
-        byte image[] = ((ByteBuffer) imgPNG.getImageData()).array();
-        int bpp = ImageStorage.getNumBands(imgPNG.getImageType());
-
-        PushbroomScaler scaler = ScalerFactory.createScaler(width, height, bpp,
-                rWidth, rHeight, smooth);
-
-        for (int y = 0; y != height; ++y) {
-            scaler.putSourceScanline(image, y * width * bpp);
-        }
-
-        return new ImageFrame(imgPNG.getImageType(), scaler.getDestination(),
-                rWidth, rHeight, rWidth * bpp, null, imgPNG.getMetadata());
-    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/DummyToolkit.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/DummyToolkit.java	Fri Jun 05 17:39:54 2015 -0700
@@ -82,6 +82,11 @@
     }
 
     @Override
+    public boolean canStartNestedEventLoop() {
+        return false;
+    }
+
+    @Override
     public Object enterNestedEventLoop(Object key) {
         throw new UnsupportedOperationException("Not supported yet.");
     }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java	Fri Jun 05 17:39:54 2015 -0700
@@ -241,6 +241,15 @@
     public abstract boolean init();
 
     /**
+     * Indicates whether or not a nested event loop can be started
+     * from the current thread in the current state. Note that a nested
+     * event loop is not allowed outside of an event handler.
+     *
+     * @return flag indicating whether a nested event loop can be started.
+     */
+    public abstract boolean canStartNestedEventLoop();
+
+    /**
      * Enter a nested event loop and block until the corresponding
      * exitNestedEventLoop call is made.
      * The key passed into this method is used to
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java	Fri Jun 05 17:39:54 2015 -0700
@@ -194,7 +194,7 @@
     private AtomicBoolean           animationRunning = new AtomicBoolean(false);
     private AtomicBoolean           nextPulseRequested = new AtomicBoolean(false);
     private AtomicBoolean           pulseRunning = new AtomicBoolean(false);
-    private boolean                 inPulse = false;
+    private int                     inPulse = 0;
     private CountDownLatch          launchLatch = new CountDownLatch(1);
 
     final int                       PULSE_INTERVAL = (int)(TimeUnit.SECONDS.toMillis(1L) / getRefreshRate());
@@ -492,6 +492,7 @@
 
     void pulse(boolean collect) {
         try {
+            inPulse++;
             if (PULSE_LOGGING_ENABLED) {
                 PulseLogger.pulseStart();
             }
@@ -500,7 +501,6 @@
                 return;
             }
             nextPulseRequested.set(false);
-            inPulse = true;
             if (animationRunnable != null) {
                 animationRunning.set(true);
                 animationRunnable.run();
@@ -510,7 +510,7 @@
             firePulse();
             if (collect) collector.renderAll();
         } finally {
-            inPulse = false;
+            inPulse--;
             endPulseRunning();
             if (PULSE_LOGGING_ENABLED) {
                 PulseLogger.pulseEnd();
@@ -555,14 +555,19 @@
         return stage;
     }
 
+    @Override public boolean canStartNestedEventLoop() {
+        return inPulse == 0;
+    }
+
     @Override public Object enterNestedEventLoop(Object key) {
         checkFxUserThread();
 
         if (key == null) {
             throw new NullPointerException();
         }
-        if (inPulse) {
-            throw new IllegalStateException("Nested event loops are allowed only while handling system events");
+
+        if (!canStartNestedEventLoop()) {
+            throw new IllegalStateException("Cannot enter nested loop during animation or layout processing");
         }
 
         if (eventLoopMap == null) {
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/print/J2DPrinterJob.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/print/J2DPrinterJob.java	Fri Jun 05 17:39:54 2015 -0700
@@ -127,6 +127,11 @@
         if (!Toolkit.getToolkit().isFxUserThread()) {
             rv = pJob2D.printDialog(printReqAttrSet);
         } else {
+            // If we are on the event thread, we need to check whether we are
+            // allowed to call a nested event handler.
+            if (!Toolkit.getToolkit().canStartNestedEventLoop()) {
+                throw new IllegalStateException("Printing is not allowed during animation or layout processing");
+            }
             rv = showPrintDialogWithNestedLoop(owner);
         }
         if (rv) {
@@ -176,6 +181,11 @@
             PageFormat pf = pJob2D.pageDialog(printReqAttrSet);
             rv = pf != null;
         } else {
+            // If we are on the event thread, we need to check whether we are
+            // allowed to call a nested event handler.
+            if (!Toolkit.getToolkit().canStartNestedEventLoop()) {
+                throw new IllegalStateException("Printing is not allowed during animation or layout processing");
+            }
             rv = showPageDialogFromNestedLoop(owner);
         }
         if (rv) {
@@ -698,6 +708,13 @@
      * and the PG code can only access it during sync.
      */
     public boolean print(PageLayout pageLayout, Node node) {
+        if (Toolkit.getToolkit().isFxUserThread()) {
+            // If we are on the event thread, we need to check whether we are
+            // allowed to call a nested event handler.
+            if (!Toolkit.getToolkit().canStartNestedEventLoop()) {
+                throw new IllegalStateException("Printing is not allowed during animation or layout processing");
+            }
+        }
 
         if (jobError || jobDone) {
             return false;
--- a/modules/graphics/src/main/java/javafx/print/PrinterJob.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/javafx/print/PrinterJob.java	Fri Jun 05 17:39:54 2015 -0700
@@ -277,10 +277,19 @@
      * <p>
      * The window <code>owner</code> may be null, but
      * if it is a visible Window, it will be used as the parent.
+     * <p>
+     * This method may be called from any thread. If it is called from the
+     * JavaFX application thread, then it must either be called from an input
+     * event handler or from the run method of a Runnable passed to
+     * {@link javafx.application.Platform#runLater Platform.runLater}.
+     * It must not be called during animation or layout processing.
+     *
      * @param owner to which to block input, or null.
      * @return false if the user opts to cancel printing, or the job
      * is not in the new state. That is if it has already started,
      * has failed, or has been cancelled, or ended.
+     * @throws IllegalStateException if this method is called during
+     * animation or layout processing.
      */
     public synchronized boolean showPrintDialog(Window owner) {
         // TBD handle owner
@@ -312,10 +321,19 @@
      * <p>
      * The window <code>owner</code> may be null, but
      * if it is a visible Window, it will be used as the parent.
+     * <p>
+     * This method may be called from any thread. If it is called from the FX
+     * application thread, then it must either be called from an input event
+     * handler or from the run method of a Runnable passed to
+     * {@link javafx.application.Platform#runLater Platform.runLater}.
+     * It must not be called during animation or layout processing.
+     *
      * @param owner to block input, or null.
      * @return false if the user opts to cancel the dialog, or the job
      * is not in the new state. That is if it has already started,
      * has failed, or has been cancelled, or ended.
+     * @throws IllegalStateException if this method is called during
+     * animation or layout processing.
      */
     public synchronized boolean showPageSetupDialog(Window owner) {
         // TBD handle owner
@@ -352,10 +370,19 @@
      * The page layout will override the job default for this page only.
      * If the job state is CANCELED, ERROR or DONE, this method will
      * return false.
+     * <p>
+     * This method may be called from any thread. If it is called from the FX
+     * application thread, then it must either be called from an input event
+     * handler or from the run method of a Runnable passed to
+     * {@link javafx.application.Platform#runLater Platform.runLater}.
+     * It must not be called during animation or layout processing.
+     *
      * @param pageLayout Layout for this page.
      * @param node The node to print.
      * @return whether rendering was successful.
      * @throws NullPointerException if either parameter is null.
+     * @throws IllegalStateException if this method is called during
+     * animation or layout processing.
      */
     public synchronized boolean printPage(PageLayout pageLayout, Node node) {
         if (jobStatus.get().ordinal() > JobStatus.PRINTING.ordinal()) {
--- a/modules/graphics/src/main/java/javafx/scene/Parent.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/javafx/scene/Parent.java	Fri Jun 05 17:39:54 2015 -0700
@@ -352,6 +352,9 @@
             }
 
             impl_markDirty(DirtyBits.PARENT_CHILDREN);
+            // Force synchronization to include the handling of invisible node
+            // so that removed list will get cleanup to prevent memory leak.
+            impl_markDirty(DirtyBits.NODE_FORCE_SYNC);
         }
 
     }) {
@@ -1807,5 +1810,11 @@
         }
         super.releaseAccessible();
     }
-
+       
+    /**
+     * Note: The only user of this method is in unit test: Parent_structure_sync_Test.
+     */
+    List<Node> test_getRemoved() {
+        return removed;
+    }
 }
--- a/modules/graphics/src/main/java/javafx/stage/Stage.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/java/javafx/stage/Stage.java	Fri Jun 05 17:39:54 2015 -0700
@@ -433,12 +433,16 @@
      * <p>
      * This method must not be called on the primary stage or on a stage that
      * is already visible.
+     * Additionally, it must either be called from an input event handler or
+     * from the run method of a Runnable passed to
+     * {@link javafx.application.Platform#runLater Platform.runLater}.
+     * It must not be called during animation or layout processing.
      * </p>
      *
      * @throws IllegalStateException if this method is called on a thread
      *     other than the JavaFX Application Thread.
-     * @throws java.lang.IllegalStateException if this method is called outside of
-     *     event handler. This includes animation callbacks, properties handlers and layout processing.
+     * @throws IllegalStateException if this method is called during
+     *     animation or layout processing.
      * @throws IllegalStateException if this method is called on the
      *     primary stage.
      * @throws IllegalStateException if this stage is already showing.
@@ -456,6 +460,10 @@
             throw new IllegalStateException("Stage already visible");
         }
 
+        if (!Toolkit.getToolkit().canStartNestedEventLoop()) {
+            throw new IllegalStateException("showAndWait is not allowed during animation or layout processing");
+        }
+
         // TODO: file a new bug; the following assertion can fail if this
         // method is called from an event handler that is listening to a
         // WindowEvent.WINDOW_HIDING event.
--- a/modules/graphics/src/main/native-glass/gtk/glass_dnd.h	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/glass_dnd.h	Fri Jun 05 17:39:54 2015 -0700
@@ -44,10 +44,10 @@
 #define DRAG_IMAGE_MAX_WIDTH 320
 #define DRAG_IMAGE_MAX_HEIGH 240
 
-#define BSWAP_32(x) (((int)(x) << 24)  | \
-          (((int)(x) << 8) & 0xff0000) | \
-          (((int)(x) >> 8) & 0xff00)   | \
-          ((int)(x)  >> 24))
+#define BSWAP_32(x) (((uint)(x) << 24)  | \
+          (((uint)(x) << 8) & 0xff0000) | \
+          (((uint)(x) >> 8) & 0xff00)   | \
+          ((uint)(x)  >> 24))
 
 class DragView {
 public:
--- a/modules/graphics/src/main/native-glass/gtk/glass_window.cpp	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/glass_window.cpp	Fri Jun 05 17:39:54 2015 -0700
@@ -117,6 +117,11 @@
             stateChangeEvent = com_sun_glass_events_WindowEvent_MAXIMIZE;
         } else {
             stateChangeEvent = com_sun_glass_events_WindowEvent_RESTORE;
+            if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
+                // in this case - the window manager will not support the programatic
+                // request to iconify - so we need to restore it now.
+                gdk_window_set_functions(gdk_window, gdk_windowManagerFunctions);
+            }
         }
 
         notify_state(stateChangeEvent);
@@ -685,6 +690,7 @@
 
     gdk_window_register_dnd(gdk_window);
 
+    gdk_windowManagerFunctions = wmf;
     if (wmf) {
         gdk_window_set_functions(gdk_window, wmf);
     }
@@ -1274,6 +1280,13 @@
             // https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1245571
             gdk_window_input_shape_combine_mask(gdk_window, NULL, 0, 0);
         }
+
+        if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
+            // in this case - the window manager will not support the programatic
+            // request to iconify - so we need to disable this until we are restored.
+            GdkWMFunction wmf = (GdkWMFunction)(gdk_windowManagerFunctions | GDK_FUNC_MINIMIZE);
+            gdk_window_set_functions(gdk_window, wmf);
+        }
         gtk_window_iconify(GTK_WINDOW(gtk_widget));
     } else {
         gtk_window_deiconify(GTK_WINDOW(gtk_widget));
--- a/modules/graphics/src/main/native-glass/gtk/glass_window.h	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/glass_window.h	Fri Jun 05 17:39:54 2015 -0700
@@ -192,6 +192,7 @@
     jobject jview;
     GtkWidget* gtk_widget;
     GdkWindow* gdk_window;
+    GdkWMFunction gdk_windowManagerFunctions;
 
     bool is_iconified;
     bool is_maximized;
--- a/modules/graphics/src/test/java/com/sun/javafx/css/StyleManagerTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/test/java/com/sun/javafx/css/StyleManagerTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -36,8 +36,6 @@
 import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
 import javafx.scene.shape.Rectangle;
-import javafx.stage.PopupWindow;
-import javafx.stage.Window;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -46,9 +44,9 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import static org.junit.Assert.*;
-import static org.junit.Assert.assertEquals;
 
 /**
  *
@@ -1078,4 +1076,43 @@
         assertEquals(StyleOrigin.USER, fillProperty.getStyleOrigin());
 
     }
+
+    @Test
+    public void testConcurrentAccess() {
+        final int NUM_THREADS = 10;
+        final Thread[] bgThreads = new Thread[NUM_THREADS];
+        final AtomicBoolean err = new AtomicBoolean(false);
+        for (int i = 0; i < NUM_THREADS; i++) {
+            Thread thr = new Thread(() -> {
+                try {
+                    for (int j = 0; j < 1000; j++) {
+                        Scene scene = new Scene(new Group());
+                        scene.setUserAgentStylesheet("com/sun/javafx/css/ua0.css");
+                        scene.getRoot().applyCss();
+                    }
+                } catch (RuntimeException ex) {
+                    err.set(true);
+                    throw ex;
+                }
+            });
+            thr.setName("MyThread-" + i);
+            thr.setDaemon(true);
+            bgThreads[i] = thr;
+        }
+
+        for (Thread thr : bgThreads) {
+            thr.start();
+        }
+
+        try {
+            for (Thread thr : bgThreads) {
+                thr.join();
+            }
+        } catch (InterruptedException ex) {
+            fail("Unexpected exception waiting for threads to finish");
+        }
+
+        assertFalse("Exception during CSS processing on BG thread", err.get());
+    }
+
 }
--- a/modules/graphics/src/test/java/com/sun/javafx/iio/ImageLoaderScalingTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/test/java/com/sun/javafx/iio/ImageLoaderScalingTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -31,6 +31,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import static org.junit.Assert.*;
+import org.junit.Ignore;
 import org.junit.Test;
 
 public class ImageLoaderScalingTest {
@@ -53,21 +54,21 @@
         return Image.convertImageFrame(imgFrames[0]);
     }
 
-    private void compare(Image img, BufferedImage bImg) {
+    private void compare(Image img, Image expectedImg) {
         assertNotNull(img);
-        assertNotNull(bImg);
+        assertNotNull(expectedImg);
         int w = img.getWidth(), h = img.getHeight();
-        double scaleX = (double)bImg.getWidth() / w;
-        double scaleY = (double)bImg.getHeight() / h;
+        double scaleX = (double)expectedImg.getWidth() / w;
+        double scaleY = (double)expectedImg.getHeight() / h;
         for (int y = 0; y < h; y++) {
             int srcY = (int) Math.floor((y + 0.5) * scaleY);
             for (int x = 0; x < w; x++) {
                 int srcX = (int) Math.floor((x + 0.5) * scaleX);
-                int expected = bImg.getRGB(srcX, srcY);
+                int expected = expectedImg.getArgb(srcX, srcY);
                 int actual = img.getArgb(x, y);
                 if (expected != actual) {
                     if (writeFiles) {
-                        writeImages(img, bImg);
+                        writeImages(img, expectedImg);
                     }
                     throw new org.junit.ComparisonFailure(
                         "pixel " + x + ", " + y + " does not match",
@@ -79,65 +80,117 @@
         }
     }
 
-    private void writePNGFile(BufferedImage bImg, String fileName) {
-        try {
-            ImageTestHelper.writeImage(bImg, fileName, "png", null);
-        } catch (IOException e) {
-            System.out.println("writePNGFile " + fileName + " failed: " + e);
-        }
-    }
-
-    private void writeImages(Image img, BufferedImage bImg) {
+    private void writeImage(Image img, String fileName) {
         int w = img.getWidth();
         int h = img.getHeight();
-        writePNGFile(bImg, "out"+w+"x"+h+"OrigJDK.png");
         int pixels[] = new int[w * h];
         img.getPixels(0, 0, w, h,
                 javafx.scene.image.PixelFormat.getIntArgbPreInstance(),
                 pixels, 0, w);
-        BufferedImage fxImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
-        fxImg.setRGB(0, 0, w, h, pixels, 0, w);
-        writePNGFile(fxImg, "out"+w+"x"+h+"ScaledFX.png");
+        BufferedImage bImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        bImg.setRGB(0, 0, w, h, pixels, 0, w);
+        try {
+            ImageTestHelper.writeImage(bImg, fileName, "png", null);
+        } catch (IOException e) {
+            System.err.println("writeImage " + fileName + " failed: " + e);
+        }
     }
 
-    private ByteArrayInputStream writePNGStream(BufferedImage bImg)
-            throws IOException
-    {
-        return ImageTestHelper.writeImageToStream(bImg, "png", null);
+    private void writeImages(Image img, Image expectedImg) {
+        int w = img.getWidth();
+        int h = img.getHeight();
+        writeImage(expectedImg, "out"+w+"x"+h+"Orig.png");
+        writeImage(img, "out"+w+"x"+h+"Scaled.png");
     }
 
-    private void scaleAndCompareImage(BufferedImage bImg, int width, int height)
-            throws Exception
+    private void scaleAndCompareImage(BufferedImage bImg, String format,
+            int width, int height) throws Exception
     {
-        ByteArrayInputStream in = writePNGStream(bImg);                
+        ByteArrayInputStream in = ImageTestHelper.writeImageToStream(bImg, format, null);
+        Image expectedImg = loadImage(in, 0, 0);
+        in.reset();
         Image img = loadImage(in, width, height);
-        compare(img, bImg);
+        compare(img, expectedImg);
     }
 
-    private void testScale(int w1, int h1, int w2, int h2) throws Exception {
-        BufferedImage bImg = createImage(w1, h1);
-        scaleAndCompareImage(bImg, w2, h2);
+    private void testScale(String format, int srcW, int srcH, int dstW, int dstH) throws Exception {
+        BufferedImage bImg = createImage(srcW, srcH);
+        scaleAndCompareImage(bImg, format, dstW, dstH);
     }
 
     @Test
-    public void testNoScale() throws Exception {
-        testScale(100, 100, 100, 100);
+    public void testNoScalePNG() throws Exception {
+        testScale("png", 100, 100, 0, 0);
+        testScale("png", 100, 100, 100, 100);
     }
 
     @Test
-    public void testAllTheScales() throws Exception {
+    public void testNoScaleBMP() throws Exception {
+        testScale("bmp", 100, 100, 0, 0);
+        testScale("bmp", 100, 100, 100, 100);
+    }
+
+    @Test
+    public void testNoScaleJPG() throws Exception {
+        testScale("jpg", 100, 100, 0, 0);
+        testScale("jpg", 100, 100, 100, 100);
+    }
+
+    @Test
+    public void testNoScaleGIF() throws Exception {
+        testScale("gif", 100, 100, 0, 0);
+        testScale("gif", 100, 100, 100, 100);
+    }
+
+    @Test
+    public void testAllTheScalesPNG() throws Exception {
+        testAllTheScales("png");
+    }
+
+    @Test
+    public void testAllTheScalesBMP() throws Exception {
+        testAllTheScales("bmp");
+    }
+
+    @Ignore // libjpeg can scale the image itself and results are unpredictable
+    @Test
+    public void testAllTheScalesJPG() throws Exception {
+        testAllTheScales("jpg");
+    }
+
+    @Test
+    public void testAllTheScalesGIF() throws Exception {
+        testAllTheScales("gif");
+    }
+
+    public void testAllTheScales(String format) throws Exception {
         BufferedImage bImg = createImage(10, 10);
         for (int h = 2; h < 20; h++) {
             for (int w = 2; w < 20; w++) {
-                scaleAndCompareImage(bImg, w, h);
-                testScale(w, h, 10, 10);
+                scaleAndCompareImage(bImg, format, w, h);
+                testScale(format, w, h, 10, 10);
             }
         }
     }
 
+    // (62.0 / 78.0) * 78 != 62
     @Test
-    public void testRT20295() throws Exception {
-        // (62.0 / 78.0) * 78 != 62
-        testScale(100, 62, 100, 78);
+    public void testRT20295_PNG() throws Exception {
+        testScale("png", 100, 62, 100, 78);
+    }
+
+    @Test
+    public void testRT20295_BMP() throws Exception {
+        testScale("bmp", 100, 62, 100, 78);
+    }
+
+    @Test
+    public void testRT20295_JPG() throws Exception {
+        testScale("jpg", 100, 62, 100, 78);
+    }
+
+    @Test
+    public void testRT20295_GIF() throws Exception {
+        testScale("gif", 100, 62, 100, 78);
     }
 }
--- a/modules/graphics/src/test/java/com/sun/javafx/pgstub/StubToolkit.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/test/java/com/sun/javafx/pgstub/StubToolkit.java	Fri Jun 05 17:39:54 2015 -0700
@@ -722,6 +722,10 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override public boolean canStartNestedEventLoop() {
+        return false;
+    }
+
     @Override public Object enterNestedEventLoop(Object key) {
         throw new UnsupportedOperationException("Not supported yet.");
     }
--- a/modules/graphics/src/test/java/javafx/scene/NodeTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/test/java/javafx/scene/NodeTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -1027,7 +1027,8 @@
 
         syncNode(g);
         syncNode(c);
-        assertEquals(1, sg.getChildren().size());
+        // Group with change in children will always be synced even if it is invisible
+        assertEquals(2, sg.getChildren().size());
         assertEquals(50.0, sc.getRadius(), 0.01);
 
         g.setVisible(true);
--- a/modules/graphics/src/test/java/javafx/scene/Parent_structure_sync_Test.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/graphics/src/test/java/javafx/scene/Parent_structure_sync_Test.java	Fri Jun 05 17:39:54 2015 -0700
@@ -28,6 +28,7 @@
 import com.sun.javafx.pgstub.StubToolkit;
 import com.sun.javafx.sg.prism.NGGroup;
 import com.sun.javafx.tk.Toolkit;
+import java.util.List;
 import javafx.scene.shape.Rectangle;
 import javafx.stage.Stage;
 import org.junit.Before;
@@ -315,4 +316,22 @@
         assertSame(r2.impl_getPeer(), peer.getChildren().get(1));
         assertSame(r3.impl_getPeer(), peer.getChildren().get(2));
     }
+
+    @Test
+    public void validateParentsRemovedList() {
+        Group parent2 = new Group();
+        parent2.getChildren().addAll(r1, r2);
+        parent.getChildren().add(parent2);
+        sync();
+        parent2.getChildren().remove(r1);
+        assertNotNull(parent2.test_getRemoved());
+        assertFalse(parent2.test_getRemoved().isEmpty());
+        sync();
+        assertTrue(parent2.test_getRemoved().isEmpty());
+        parent2.getChildren().remove(r2);
+        parent.setVisible(false);
+        assertFalse(parent2.test_getRemoved().isEmpty());
+        sync();
+        assertTrue(parent2.test_getRemoved().isEmpty());
+    }
 }
--- a/modules/media/src/main/java/com/sun/javafx/media/PrismMediaFrameHandler.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/media/src/main/java/com/sun/javafx/media/PrismMediaFrameHandler.java	Fri Jun 05 17:39:54 2015 -0700
@@ -74,7 +74,9 @@
     
     /**
      * This should only ever be called during a render cycle. Any other time it
-     * will return null.
+     * will return null. Note that a returned texture should be unlocked when
+     * the caller no longer needs it.
+     * 
      * @param g the Graphics context about to be rendered into
      * @return the current media texture valid for rendering into <code>g</code>
      * or null if called outside a render cycle
--- a/modules/web/src/main/java/com/sun/javafx/webkit/UIClientImpl.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/web/src/main/java/com/sun/javafx/webkit/UIClientImpl.java	Fri Jun 05 17:39:54 2015 -0700
@@ -274,7 +274,8 @@
             //Image need to be created by target request only.
             //QuantumClipboard.putContent have to be rewritten in Glass manner
             //with postponed data requests (DelayedCallback data object).
-            Object platformImage = image.getPlatformImage();
+            Object platformImage = image.getWidth() > 0 && image.getHeight() > 0 ?
+                    image.getPlatformImage() : null;
             if (platformImage != null) {
                 try {
                     File temp = File.createTempFile("jfx", ".png");
--- a/modules/web/src/main/java/com/sun/javafx/webkit/prism/WCMediaPlayerImpl.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/modules/web/src/main/java/com/sun/javafx/webkit/prism/WCMediaPlayerImpl.java	Fri Jun 05 17:39:54 2015 -0700
@@ -357,6 +357,7 @@
             g.drawTexture(texture,
                     x, y, x + w, y + h,
                     0f, 0f, texture.getContentWidth(), texture.getContentHeight());
+            texture.unlock();
         } else {
             if (verbose) log.log(Level.FINEST, "  (Prism)renderImpl, texture is null, draw black rect");
             gc.fillRect(x, y, w, h, 0xFF000000);
--- a/tests/system/src/test/java/javafx/stage/ShowAndWaitTest.java	Thu Jun 04 02:26:02 2015 -0700
+++ b/tests/system/src/test/java/javafx/stage/ShowAndWaitTest.java	Fri Jun 05 17:39:54 2015 -0700
@@ -31,11 +31,18 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import javafx.animation.KeyFrame;
+import javafx.animation.Timeline;
 import javafx.application.Application;
 import javafx.application.Platform;
+import javafx.print.PrinterJob;
 import javafx.scene.Group;
 import javafx.scene.Scene;
+import javafx.scene.control.Alert;
 import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.util.Duration;
 import junit.framework.AssertionFailedError;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -647,4 +654,151 @@
         }
     }
 
+    // Verify that Stage.showAndWait throws an exception if called from an
+    // animation timeline.
+    @Test
+    public void testTimeline() throws Throwable {
+        ensureTest1();
+
+        final CountDownLatch animationDone = new CountDownLatch(1);
+        final AtomicReference<Throwable> error = new AtomicReference<>(null);
+
+        KeyFrame kf = new KeyFrame(Duration.millis(200), e -> {
+            try {
+                tmpStage1 = new TestStage(modality);
+                stages.add(tmpStage1);
+                assertFalse(tmpStage1.isPrimary());
+                assertFalse(tmpStage1.isShowing());
+                try {
+                    tmpStage1.showAndWait();
+                    fail("Did not get expected exception from showAndWait");
+                } catch (IllegalStateException ex) {
+                    // Good
+                }
+                assertFalse(tmpStage1.isShowing());
+            } catch (Throwable t) {
+                error.set(t);
+            }
+            animationDone.countDown();
+        });
+        Timeline timeline = new Timeline(kf);
+        timeline.play();
+
+        try {
+            if (!animationDone.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                fail("Timeout waiting for animation");
+            }
+        } catch (InterruptedException ex) {
+            fail("Unexpected exception: " + ex);
+        }
+
+        final Throwable t = error.get();
+        if (t != null) {
+            throw t;
+        }
+
+        assertFalse(tmpStage1.isShowing());
+    }
+
+    // Verify that Alert.showAndWait throws an exception if called from an
+    // animation timeline.
+    @Test
+    public void testTimelineDialog() throws Throwable {
+        ensureTest1();
+
+        final CountDownLatch animationDone = new CountDownLatch(1);
+        final AtomicReference<Throwable> error = new AtomicReference<>(null);
+
+        KeyFrame kf = new KeyFrame(Duration.millis(200), e -> {
+            Alert alert = null;
+            try {
+                alert = new Alert(Alert.AlertType.INFORMATION);
+                assertFalse(alert.isShowing());
+                try {
+                    alert.showAndWait();
+                    fail("Did not get expected exception from showAndWait");
+                } catch (IllegalStateException ex) {
+                    // Good
+                }
+                assertFalse(alert.isShowing());
+            } catch (Throwable t) {
+                error.set(t);
+                try {
+                    if (alert.isShowing()) {
+                        alert.close();
+                    }
+                } catch (RuntimeException ex) {}
+            }
+            animationDone.countDown();
+        });
+        Timeline timeline = new Timeline(kf);
+        timeline.play();
+
+        try {
+            if (!animationDone.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                fail("Timeout waiting for animation");
+            }
+        } catch (InterruptedException ex) {
+            fail("Unexpected exception: " + ex);
+        }
+
+        final Throwable t = error.get();
+        if (t != null) {
+            throw t;
+        }
+    }
+
+    // Verify that printing throws an exception if called from an
+    // animation timeline.
+    @Test
+    public void testTimelinePrint() throws Throwable {
+        ensureTest1();
+
+        final CountDownLatch animationDone = new CountDownLatch(1);
+        final AtomicReference<Throwable> error = new AtomicReference<>(null);
+
+        KeyFrame kf = new KeyFrame(Duration.millis(200), e -> {
+            try {
+                PrinterJob job = PrinterJob.createPrinterJob();
+                try {
+                    job.showPrintDialog(myApp.primaryStage);
+                    fail("Did not get expected exception from showPrintDialog");
+                } catch (IllegalStateException ex) {
+                    // Good
+                }
+                try {
+                    job.showPageSetupDialog(myApp.primaryStage);
+                    fail("Did not get expected exception from showPageSetupDialog");
+                } catch (IllegalStateException ex) {
+                    // Good
+                }
+                try {
+                    Rectangle rect = new Rectangle(200, 100, Color.GREEN);
+                    job.printPage(rect);
+                    fail("Did not get expected exception from printPage");
+                } catch (IllegalStateException ex) {
+                    // Good
+                }
+            } catch (Throwable t) {
+                error.set(t);
+            }
+            animationDone.countDown();
+        });
+        Timeline timeline = new Timeline(kf);
+        timeline.play();
+
+        try {
+            if (!animationDone.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                fail("Timeout waiting for animation");
+            }
+        } catch (InterruptedException ex) {
+            fail("Unexpected exception: " + ex);
+        }
+
+        final Throwable t = error.get();
+        if (t != null) {
+            throw t;
+        }
+    }
+
 }