changeset 6944:e4d920161c61

RT-35260: add unit tests, update cssref, fixes for unit test failures
author David Grieve<david.grieve@oracle.com>
date Fri, 02 May 2014 17:33:21 -0400
parents 14a7fde042ef
children abc855ae09c0
files modules/graphics/src/main/docs/javafx/scene/doc-files/cssref.html modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java modules/graphics/src/main/java/javafx/scene/Scene.java modules/graphics/src/main/java/javafx/scene/SubScene.java modules/graphics/src/test/java/com/sun/javafx/css/StyleManagerTest.java modules/graphics/src/test/resources/com/sun/javafx/css/ua0.css modules/graphics/src/test/resources/com/sun/javafx/css/ua1.css modules/graphics/src/test/resources/com/sun/javafx/css/ua2.css
diffstat 8 files changed, 1115 insertions(+), 373 deletions(-) [+]
line wrap: on
line diff
--- a/modules/graphics/src/main/docs/javafx/scene/doc-files/cssref.html	Fri May 02 17:19:28 2014 -0400
+++ b/modules/graphics/src/main/docs/javafx/scene/doc-files/cssref.html	Fri May 02 17:33:21 2014 -0400
@@ -187,11 +187,13 @@
       <li><a href="#intro">Introduction</a>
         <ul>
           <li><a href="#introscenegraph">CSS and the JavaFX Scene Graph</a></li>
+          <li><a href="#introstylesheets">Scene, Parent and SubScene Stylesheets</a></li>
+          <li><a href="#intronaming">Naming Conventions</a></li>
           <li><a href="#intropublicapi">CSS Public API</a></li>
-          <li><a href="#introlimitations">Limitations</a></li>
           <li><a href="#introinheritance">Inheritance</a></li>
           <li><a href="#introexamples">Examples</a></li>
           <li><a href="#introparserwarnings">Understanding Parser Warnings</a></li>
+          <li><a href="#introlimitations">Limitations</a></li>
         </ul>
       </li>
       <li><a href="#types">Types</a>
@@ -435,7 +437,6 @@
         such as MouseEvent.MOUSE_ENTERED which triggers the &quot;hover&quot; state, are
         applied on then next pulse following the event.
     </p>
-
     <p>
         <a href="http://www.w3.org/TR/css3-selectors/">CSS selectors</a> are used to match styles to scene&#8209;graph
         nodes.
@@ -480,6 +481,7 @@
         the appropriate type and is then assigned to an instance variable of the
         JavaFX object.
     </p>
+    <h3><a name="introstylesheets" id="introstylesheets">Scene, Parent and SubScene Stylesheets</a></h3>
     <p>
         CSS styles can come from style sheets or inline styles. Style sheets are
         loaded from the URLs specified in the
@@ -502,6 +504,27 @@
         inline styles, the style sheets of all its ancestors, and any style sheets
         from the Scene.
     </p>
+    <p>
+        Beginning with JavaFX 8u20, the Scene class has a
+        <a href="../../../javafx/scene/Scene.html#getUserAgentStylesheet--">getUserAgentStylesheet</a> property,
+        allowing a user&#8209;style sheet to be set on a Scene. This allows a Scene
+        to have a set of user&#8209;agent styles distinct from the platform default. When a user&#8209;agent
+        stylesheet is set on a Scene, the user&#8209;agent styles are used instead of the styles from the
+        platform default user&#8209;agent stylesheet.
+    </p>
+    <p>
+        Beginning with JavaFX 8u20, the SubScene class has a
+        <a href="../../../javafx/scene/SubScene.html#getUserAgentStylesheet--">getUserAgentStylesheet</a> property,
+        allowing a user&#8209;style sheet to be set on a SubScene. This allows a SubScene
+        of the scene&#8209;graph to have set of user&#8209;agent styles distinct from the platform default
+        or from the Scene in which the SubScene is contained. When a user&#8209;agent
+        stylesheet is set on a SubScene, the user&#8209;agent styles are used instead of the styles from the
+        platform default user&#8209;agent stylesheet or any user&#8209;agent stylesheet set on the Scene.
+    </p>
+    <p>It is important to note that styles from a stylesheet added to a Scene or Parent, do not affect
+        a SubScene which is a child or descendent of the Scene or Parent. Unless a user&#8209;agent has
+        been set on the SubScene, the SubScene will get styles
+        from the a Scene's user&#8209;agent stylesheet or the platform user&#8209;agent stylesheet.</p>
     The implementation allows designers to style an application by using style
     sheets to override property values set from code. For example, a call to <code>rectangle.setFill(Color.YELLOW)</code>
     can be overridden by an inline&#8209;style or a style from an author stylesheet. This has implications for
@@ -512,6 +535,7 @@
     or Parent style sheet. Inline styles have highest precedence. Style sheets
     from a Parent instance are considered to be more specific than those styles
     from Scene style sheets.</cite>
+    <h3><a name="intronaming" id="introsnaming">Naming Conventions</a></h3>
     <p>Naming conventions have been established for deriving CSS style&#8209;class
         names from JavaFX class names, and for deriving CSS property names from
         JavaFX variable names. Note that this is only a naming convention; there
@@ -530,30 +554,6 @@
     <h3><a name="intropublicapi" id="intropublicapi">CSS Public API</a></h3>
     Beginning with JavaFX 8.0, public API is available for developers to create styleable properties and manage
     pseudo-class state. Refer to <a href="../../../javafx/css/package-summary.html">javafx.css</a> for details.
-    <h3><a name="introlimitations" id="introlimitations">Limitations</a></h3>
-    <p> While the JavaFX CSS parser will parse valid CSS syntax, it is not a
-        fully compliant CSS parser. One should not expect the parser to handle
-        syntax not specified in this document.</p>
-    <p>With the exception of @font&#8209;face, @-keyword statements are ignored.</p>
-    <p>The structural pseudo&#8209;classes are not supported. </p>
-    <p>The ":active" and ":focus" dynamic pseudo&#8209;classes are not supported.
-        However, <a href="#node">Nodes</a> do support the ":pressed" and
-        ":focused" pseudo&#8209;classes, which are similar. </p>
-    <p>The ":link" and ":visited" pseudo&#8209;classes are not supported in general.
-        However, <a href="#hyperlink">Hyperlink</a> objects can be styled, and
-        they support the ":visited" pseudo&#8209;class. </p>
-    <p>JavaFX CSS does not support comma-separated series of font family names
-        in the -fx-font-family property. The optional line height parameter when
-        specifying fonts is not supported. There is no equivalent for the
-        font-variant property.</p>
-    <p>JavaFX CSS uses the HSB color model instead of the HSL color model. </p>
-    <p>If a property of a node is initialized by calling the set method of the
-    property, the CSS implementation will see this as a user set value and the
-    value will not be overwritten by a style from a user agent style
-    sheet.</p>
-    <p>When parsing a <a href="http://www.w3.org/TR/CSS2/syndata.html#uri">URI</a>,
-    the parser doesn't handle URI escapes nor \&lt;hex-digit&gt;[1,6] code points.</p>
-
     <h3><a name="introinheritance" id="introinheritance">Inheritance</a></h3>
     <p>CSS also provides for certain properties to be inherited by default, or
         to be inherited if the property value is 'inherit'. If a value is
@@ -657,6 +657,30 @@
         to the errors property of com.sun.javafx.css.StyleManager. This is not
         public API and is subject to change. <br>
     </p>
+    <h3><a name="introlimitations" id="introlimitations">Limitations</a></h3>
+    <p> While the JavaFX CSS parser will parse valid CSS syntax, it is not a
+        fully compliant CSS parser. One should not expect the parser to handle
+        syntax not specified in this document.</p>
+    <p>With the exception of @font&#8209;face and @import, @-keyword statements are ignored.</p>
+    <p>The structural pseudo&#8209;classes are not supported. </p>
+    <p>The ":active" and ":focus" dynamic pseudo&#8209;classes are not supported.
+        However, <a href="#node">Nodes</a> do support the ":pressed" and
+        ":focused" pseudo&#8209;classes, which are similar. </p>
+    <p>The ":link" and ":visited" pseudo&#8209;classes are not supported in general.
+        However, <a href="#hyperlink">Hyperlink</a> objects can be styled, and
+        they support the ":visited" pseudo&#8209;class. </p>
+    <p>JavaFX CSS does not support comma-separated series of font family names
+        in the -fx-font-family property. The optional line height parameter when
+        specifying fonts is not supported. There is no equivalent for the
+        font-variant property.</p>
+    <p>JavaFX CSS uses the HSB color model instead of the HSL color model. </p>
+    <p>If a property of a node is initialized by calling the set method of the
+        property, the CSS implementation will see this as a user set value and the
+        value will not be overwritten by a style from a user agent style
+        sheet.</p>
+    <p>When parsing a <a href="http://www.w3.org/TR/CSS2/syndata.html#uri">URI</a>,
+        the parser doesn't handle URI escapes nor \&lt;hex-digit&gt;[1,6] code points.</p>
+
     <h2><a name="types" id="types">Types</a></h2>
     <h3><a name="typeinherit" id="typeinherit">inherit</a></h3>
     <p>Each property has a type, which determines what kind of value and the
--- a/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java	Fri May 02 17:19:28 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java	Fri May 02 17:33:21 2014 -0400
@@ -46,13 +46,7 @@
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import javafx.collections.FXCollections;
@@ -66,8 +60,6 @@
 import javafx.stage.Window;
 import com.sun.javafx.css.parser.CSSParser;
 import java.util.Map.Entry;
-import java.util.Set;
-import java.util.WeakHashMap;
 
 import javafx.css.CssMetaData;
 import javafx.css.PseudoClass;
@@ -169,11 +161,12 @@
     }
 
     /**
-     * Each Scene has its own cache. If a scene is closed,
-     * then StyleManager is told to forget the scene and it's cache is annihilated.
+     * A map from a parent to its style cache. The parent is either a Scene root, or a
+     * Parent with author stylesheets. If a Scene or Parent is removed from the scene,
+     * it's cache is annihilated.
      */
-    private static final Map<Parent, CacheContainer> cacheContainerMap
-            = new WeakHashMap<>();
+    // package for testing
+    static final Map<Parent, CacheContainer> cacheContainerMap = new WeakHashMap<>();
 
 
     private CacheContainer getCacheContainer(Styleable styleable, SubScene subScene) {
@@ -239,16 +232,22 @@
         return container.getStyleMap(smapId);
     }
 
-   /**
-     * This stylesheet represents the "default" set of styles for the entire
-     * platform. This is typically only set by the UI Controls module, and
-     * otherwise is generally null. Whenever this variable changes (via the
-     * setDefaultUserAgentStylesheet function call) then we will end up clearing
-     * all of the caches.
+    /**
+     * A list of user-agent stylesheets from Scene or SubScene.
+     * The order of the entries in this list does not matter since a Scene or
+     * SubScene will only have zero or one user-agent stylesheets.
      */
-    private final Map<String,Integer> userAgentStylesheets = new HashMap<>();
-    private final List<StylesheetContainer> userAgentStylesheetContainers = new ArrayList<>();
-    private final List<String> platformUserAgentStylesheets = new ArrayList<>();
+    // package for testing
+    final List<StylesheetContainer> userAgentStylesheetContainers = new ArrayList<>();
+    /**
+     * A list of user-agent stylesheet urls from calling setDefaultUserAgentStylesheet and
+     * addUserAgentStylesheet. The order of entries this list matters. The zeroth element is
+     * _the_ platform default.
+     */
+    // package for testing
+    final List<StylesheetContainer> platformUserAgentStylesheetContainers = new ArrayList<>();
+    // package for testing
+    boolean hasDefaultUserAgentStylesheet = false;
 
     ////////////////////////////////////////////////////////////////////////////
     //
@@ -270,12 +269,8 @@
      * StylesheetContainer<Scene> are created and added to sceneStylesheetMap in
      * the method updateStylesheets
      */
-    private static class StylesheetContainer {
-
-        @FunctionalInterface
-        static interface Referent {
-            void addReferenceTo(StylesheetContainer c);
-        }
+    // package for testing
+    static class StylesheetContainer {
 
         // the stylesheet uri
         final String fname;
@@ -284,8 +279,8 @@
         // the parents or scenes that use this stylesheet. Typically, this list
         //  should be very small.
         final SelectorPartitioning selectorPartitioning;
+
         // who uses this stylesheet?
-        final RefList<Scene> sceneUsers;
         final RefList<Parent> parentUsers;
 
         // RT-24516 -- cache images coming from this stylesheet.
@@ -327,7 +322,6 @@
                 selectorPartitioning = null;
             }
 
-            this.sceneUsers = new RefList<Scene>();
             this.parentUsers = new RefList<Parent>();
 
             // this just holds a hard reference to the image
@@ -368,10 +362,9 @@
 
     /*
      * A list that holds references. Used by StylesheetContainer.
-     * We only ever add to this list, or the whole container gets thrown
-     * away.
      */
-    private static class RefList<K> {
+    // package for testing
+    static class RefList<K> {
 
         final List<Reference<K>> list = new ArrayList<Reference<K>>();
 
@@ -394,14 +387,46 @@
             list.add(new WeakReference<K>(key));
         }
 
+        void remove(K key) {
+
+            for (int n=list.size()-1; 0<=n; --n) {
+                final Reference<K> ref = list.get(n);
+                final K k = ref.get();
+                if (k == null) {
+                    // stale reference, remove it.
+                    list.remove(n);
+                } else {
+                    // already have it, bail
+                    if (k == key) {
+                        list.remove(n);
+                        return;
+                    }
+                }
+            }
+        }
+
+        // for unit testing
+        boolean contains(K key) {
+            for (int n=list.size()-1; 0<=n; --n) {
+                final Reference<K> ref = list.get(n);
+                final K k = ref.get();
+                if (k == key) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
      * A map from String => Stylesheet. If a stylesheet for the
      * given URL has already been loaded then we'll simply reuse the stylesheet
      * rather than loading a duplicate.
+     * This list is for author stylesheets and not for user-agent stylesheets. User-agent
+     * stylesheets are either platformUserAgentStylesheetContainers or userAgentStylesheetContainers
      */
-    private final Map<String,StylesheetContainer> stylesheetContainerMap = new HashMap<>();
+    // package for unit testing
+    final Map<String,StylesheetContainer> stylesheetContainerMap = new HashMap<>();
 
 
     /**
@@ -409,23 +434,30 @@
      */
     public void forget(final Scene scene) {
 
-        Set<Entry<Parent,CacheContainer>> entrySet = cacheContainerMap.entrySet();
-        Iterator<Entry<Parent,CacheContainer>> iterator = entrySet.iterator();
-        while(iterator.hasNext()) {
-            Entry<Parent,CacheContainer> entry = iterator.next();
-            Parent parent = entry.getKey();
-            CacheContainer container = entry.getValue();
-            if (parent.getScene() == scene) {
-                iterator.remove();
-                StyleManager.getInstance().forget(parent);
-                container.clearCache();
+        if (scene == null) return;
+
+        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())) {
+
+            for(int n=0,nMax=userAgentStylesheetContainers.size(); n<nMax; 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 this scene and any parents belonging to this scene from the
-        // stylesheetContainerMap
+        // remove any parents belonging to this scene from the stylesheetContainerMap
         //
         Set<Entry<String,StylesheetContainer>> stylesheetContainers = stylesheetContainerMap.entrySet();
         Iterator<Entry<String,StylesheetContainer>> iter = stylesheetContainers.iterator();
@@ -435,17 +467,6 @@
             Entry<String,StylesheetContainer> entry = iter.next();
             StylesheetContainer container = entry.getValue();
 
-            Iterator<Reference<Scene>> sceneIter = container.sceneUsers.list.iterator();
-            while (sceneIter.hasNext()) {
-
-                Reference<Scene> ref = sceneIter.next();
-                Scene _scene = ref.get();
-
-                if (_scene == scene || _scene == null) {
-                    sceneIter.remove();
-                }
-            }
-
             Iterator<Reference<Parent>> parentIter = container.parentUsers.list.iterator();
             while (parentIter.hasNext()) {
 
@@ -453,12 +474,12 @@
                 Parent _parent = ref.get();
 
                 if (_parent == null || _parent.getScene() == scene || _parent.getScene() == null) {
+                    ref.clear();
                     parentIter.remove();
                 }
             }
 
-            if (container.sceneUsers.list.isEmpty() &&
-                    container.parentUsers.list.isEmpty()) {
+            if (container.parentUsers.list.isEmpty()) {
                 iter.remove();
             }
         }
@@ -499,23 +520,7 @@
     }
 
     private void stylesheetRemoved(Scene scene, String fname) {
-
-        StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
-        if (stylesheetContainer == null) return;
-
-        final Iterator<Reference<Scene>> iterator = stylesheetContainer.sceneUsers.list.iterator();
-        while (iterator.hasNext()) {
-            Reference<Scene> ref = iterator.next();
-            Scene s = ref.get();
-            if (s == null || s == scene) {
-                ref.clear();
-                iterator.remove();
-            }
-        }
-
-        if (stylesheetContainer.parentUsers.list.isEmpty() && stylesheetContainer.sceneUsers.list.isEmpty()) {
-            removeStylesheetContainer(stylesheetContainer);
-        }
+        stylesheetRemoved(scene.getRoot(), fname);
     }
 
     /**
@@ -524,6 +529,9 @@
      */
     public void forget(Parent parent) {
 
+        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()) {
@@ -533,11 +541,9 @@
             if (parent == key) {
                 iterator.remove();
                 container.clearCache();
-                break;
             }
         }
 
-        // RT-34863 - clean up CSS cache when Parent is removed from scene-graph
         final List<String> stylesheets = parent.getStylesheets();
         if (stylesheets != null && !stylesheets.isEmpty()) {
             for (String fname : stylesheets) {
@@ -569,21 +575,83 @@
     private void stylesheetRemoved(Parent parent, String fname) {
 
         StylesheetContainer stylesheetContainer = stylesheetContainerMap.get(fname);
+
         if (stylesheetContainer == null) return;
 
-        final Iterator<Reference<Parent>> iterator = stylesheetContainer.parentUsers.list.iterator();
-        while (iterator.hasNext()) {
-            Reference<Parent> ref = iterator.next();
-            Parent p = ref.get();
-            if (p == null || p == parent) {
-                ref.clear();
-                iterator.remove();
+        stylesheetContainer.parentUsers.remove(parent);
+
+        if (stylesheetContainer.parentUsers.list.isEmpty()) {
+            removeStylesheetContainer(stylesheetContainer);
+        }
+    }
+
+    /**
+     * called from Window when the scene is closed.
+     */
+    public void forget(final SubScene subScene) {
+
+        if (subScene == null) return;
+        final Parent subSceneRoot = subScene.getRoot();
+
+        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())) {
+
+            for(int n=0,nMax=userAgentStylesheetContainers.size(); n<nMax; n++) {
+                StylesheetContainer container = userAgentStylesheetContainers.get(n);
+                if (sceneUserAgentStylesheet.equals(container.fname)) {
+                    container.parentUsers.remove(subScene.getRoot());
+                    if (container.parentUsers.list.size() == 0) {
+                        userAgentStylesheetContainers.remove(n);
+                    }
+                }
             }
         }
 
-        if (stylesheetContainer.parentUsers.list.isEmpty() && stylesheetContainer.sceneUsers.list.isEmpty()) {
-            removeStylesheetContainer(stylesheetContainer);
+        //
+        // remove any parents belonging to this SubScene from the stylesheetContainerMap
+        //
+        Set<Entry<String,StylesheetContainer>> stylesheetContainers = stylesheetContainerMap.entrySet();
+        Iterator<Entry<String,StylesheetContainer>> iter = stylesheetContainers.iterator();
+
+        while(iter.hasNext()) {
+
+            Entry<String,StylesheetContainer> entry = iter.next();
+            StylesheetContainer container = entry.getValue();
+
+            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 = _parent.getParent();
+                    }
+                }
+            }
+
+            // forget(_parent) will remove the container if the parentUser's list is empty
+            // if (container.parentUsers.list.isEmpty()) {
+            //    iter.remove();
+            // }
         }
+
     }
 
     private void removeStylesheetContainer(StylesheetContainer stylesheetContainer) {
@@ -630,21 +698,8 @@
         // might have come from this stylesheet
         cleanUpImageCache(fname);
 
-        final List<Reference<Scene>> sceneList = stylesheetContainer.sceneUsers.list;
         final List<Reference<Parent>> parentList = stylesheetContainer.parentUsers.list;
 
-        for (int n=sceneList.size()-1; 0<=n; --n) {
-
-            final Reference<Scene> ref = sceneList.remove(n);
-            final Scene scene = ref.get();
-            ref.clear();
-            if (scene == null) {
-                continue;
-            }
-
-            scene.getRoot().impl_reapplyCSS();
-        }
-
         for (int n=parentList.size()-1; 0<=n; --n) {
 
             final Reference<Parent> ref = parentList.remove(n);
@@ -664,49 +719,6 @@
 
     }
 
-    // RT-22565: Called from parentStylesheetsChanged to clear the cache entries
-    // for parents and scenes that use the same stylesheet
-    private void clearCache(StylesheetContainer sc) {
-
-        if (sc == null) return;
-
-        // clean up image cache by removing images from the cache that
-        // might have come from this stylesheet
-        cleanUpImageCache(sc.fname);
-
-        final List<Reference<Scene>> sceneList = sc.sceneUsers.list;
-        final List<Reference<Parent>> parentList = sc.parentUsers.list;
-
-        for (int n=sceneList.size()-1; 0<=n; --n) {
-
-            final Reference<Scene> ref = sceneList.remove(n);
-            final Scene scene = ref.get();
-            ref.clear();
-            if (scene == null) {
-                continue;
-            }
-
-            scene.getRoot().impl_reapplyCSS();
-        }
-
-        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();
-        }
-    }
-
     ////////////////////////////////////////////////////////////////////////////
     //
     // Image caching
@@ -1125,32 +1137,33 @@
     // For RT-20643
     public void addUserAgentStylesheet(Scene scene, String url) {
 
-        String fname = null;
-        // nothing to add
-        if (url == null ||  (fname = url.trim()).isEmpty()) {
+        if (url == null ) {
+            throw new IllegalArgumentException("null arg url");
+        }
+
+        final String fname = url.trim();
+        if (fname.isEmpty()) {
             return;
         }
 
-        if (platformUserAgentStylesheets.contains(fname)) {
-            // already have it
-            return;
-        } else {
-            platformUserAgentStylesheets.add(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;
+            }
         }
 
         // RT-20643
         CssError.setCurrentScene(scene);
 
-        int index = userAgentStylesheetContainers.size();
-        userAgentStylesheets.put(fname,index);
-
         final Stylesheet ua_stylesheet = loadStylesheet(fname);
-        userAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
+        platformUserAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
 
         if (ua_stylesheet != null) {
             ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-            userAgentStylesheetsChanged();
         }
+        userAgentStylesheetsChanged();
 
         // RT-20643
         CssError.setCurrentScene(null);
@@ -1165,28 +1178,31 @@
      */
     public void addUserAgentStylesheet(Scene scene, Stylesheet ua_stylesheet) {
 
-        String url = ua_stylesheet != null ? ua_stylesheet.getUrl() : null;
-        String fname = url != null ? url.trim() : "";
+        if (ua_stylesheet == null ) {
+            throw new IllegalArgumentException("null arg ua_stylesheet");
+        }
 
-        if (platformUserAgentStylesheets.contains(fname)) {
-            // already have it
-            return;
-        } else {
-            platformUserAgentStylesheets.add(fname);
+        // null url is ok, just means that it is a stylesheet not loaded from a file
+        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;
+            }
         }
 
         // RT-20643
         CssError.setCurrentScene(scene);
 
-        int index = userAgentStylesheetContainers.size();
-        userAgentStylesheets.put(fname,index);
-
-        userAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
+        platformUserAgentStylesheetContainers.add(new StylesheetContainer(fname, ua_stylesheet));
 
         if (ua_stylesheet != null) {
             ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-            userAgentStylesheetsChanged();
         }
+        userAgentStylesheetsChanged();
 
         // RT-20643
         CssError.setCurrentScene(null);
@@ -1210,60 +1226,45 @@
     // For RT-20643
     public void setDefaultUserAgentStylesheet(Scene scene, String url) {
 
-        String fname = null;
-        if (url == null || (fname = url.trim()).isEmpty()) {
+        final String fname = (url != null) ? url.trim() : null;
+        if (fname == null || fname.isEmpty()) {
             throw new IllegalArgumentException("null arg url");
         }
 
-        // make sure this file is the first in the list
-        platformUserAgentStylesheets.remove(fname);
-        platformUserAgentStylesheets.add(0,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);
+                    }
+                }
+                return;
+            }
+        }
 
         // RT-20643
         CssError.setCurrentScene(scene);
 
-        if (!userAgentStylesheets.containsKey(fname)) {
+        final Stylesheet ua_stylesheet = loadStylesheet(fname);
+        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;
 
-            final Stylesheet ua_stylesheet = loadStylesheet(fname);
-            if (ua_stylesheet != null) {
-                ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-
-                // remap indices in userAgentStylesheet map to match userAgentStylesheetContainers
-                userAgentStylesheets.replaceAll((k, v) -> {
-                    // bump the index up by one
-                    return Integer.valueOf(v.intValue() + 1);
-                });
-                userAgentStylesheets.put(fname, Integer.valueOf(0));
-
-                StylesheetContainer sc = new StylesheetContainer(fname, ua_stylesheet);
-                userAgentStylesheetContainers.add(0, sc);
-
-                userAgentStylesheetsChanged();
-            }
-
-        } else {
-
-            // this stylesheet has been added already, make sure it is the zeroth element
-            final int fromIndex = userAgentStylesheets.get(fname);
-
-            // If this stylesheet has already been added and is the zeroth stylesheet,
-            // then it is already the default and we can just return;
-            if (fromIndex == 0) return;
-
-            // remap indices in userAgentStylesheet map to match userAgentStylesheetContainers
-            userAgentStylesheets.replaceAll((k, v) -> {
-                // bump the index up by one for all indices less than fromIndex
-                int i = v.intValue();
-                if (i < fromIndex) return Integer.valueOf(++i);
-                else return v;
-            });
-
-            // Otherwise, move this stylesheet to be the zeroth element.
-            userAgentStylesheetContainers.add(0, userAgentStylesheetContainers.remove(fromIndex));
-            userAgentStylesheets.replace(fname, 0);
-
-            userAgentStylesheetsChanged();
+        if (ua_stylesheet != null) {
+            ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
         }
+        userAgentStylesheetsChanged();
 
         // RT-20643
         CssError.setCurrentScene(null);
@@ -1274,60 +1275,44 @@
      * Set the user agent stylesheet. This is the base default stylesheet for
      * the platform
      */
-    public void setDefaultUserAgentStylesheet(Stylesheet stylesheet) {
+    public void setDefaultUserAgentStylesheet(Stylesheet ua_stylesheet) {
 
-        if (stylesheet == null ) {
+        if (ua_stylesheet == null ) {
             throw new IllegalArgumentException("null arg ua_stylesheet");
         }
 
-        String url = stylesheet.getUrl();
-        String fname = null;
-        if (url == null || (fname = url.trim()).isEmpty()) {
-            throw new IllegalArgumentException("null arg url");
+        // null url is ok, just means that it is a stylesheet not loaded from a file
+        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);
+                    }
+                }
+                return;
+            }
         }
 
-        if (!userAgentStylesheets.containsKey(fname)) {
+        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;
 
-            if (stylesheet != null) {
-                stylesheet.setOrigin(StyleOrigin.USER_AGENT);
-
-                // remap indices in userAgentStylesheet map to match userAgentStylesheetContainers
-                userAgentStylesheets.replaceAll((k, v) -> {
-                    // bump the index up by one
-                    return Integer.valueOf(v.intValue() + 1);
-                });
-                userAgentStylesheets.put(fname, Integer.valueOf(0));
-
-                StylesheetContainer sc = new StylesheetContainer(fname, stylesheet);
-                userAgentStylesheetContainers.add(0, sc);
-
-                userAgentStylesheetsChanged();
-            }
-
-        } else {
-
-            // this stylesheet has been added already, make sure it is the zeroth element
-
-            final int fromIndex = userAgentStylesheets.get(fname);
-
-            // If this stylesheet has already been added and is the zeroth stylesheet,
-            // then it is already the default and we can just return;
-            if (fromIndex == 0) return;
-
-            // remap indices in userAgentStylesheet map to match userAgentStylesheetContainers
-            userAgentStylesheets.replaceAll((k, v) -> {
-                // bump the index up by one for all indices less than fromIndex
-                int i = v.intValue();
-                if (i < fromIndex) return Integer.valueOf(++i);
-                else return v;
-            });
-
-            // Otherwise, move this stylesheet to be the zeroth element.
-            userAgentStylesheetContainers.add(0, userAgentStylesheetContainers.remove(fromIndex));
-            userAgentStylesheets.replace(fname, 0);
-
-            userAgentStylesheetsChanged();
-        }
+        ua_stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+        userAgentStylesheetsChanged();
 
         // RT-20643
         CssError.setCurrentScene(null);
@@ -1353,7 +1338,7 @@
 
     }
 
-    private List<StylesheetContainer> processStylesheets(List<String> stylesheets, StylesheetContainer.Referent referent) {
+    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++) {
@@ -1384,7 +1369,7 @@
                 // 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.
-                referent.addReferenceTo(container);
+                container.parentUsers.add(parent);
 
             } else {
                 final Stylesheet stylesheet = loadStylesheet(fname);
@@ -1396,7 +1381,7 @@
                 // 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.
-                referent.addReferenceTo(container);
+                container.parentUsers.add(parent);
                 stylesheetContainerMap.put(fname, container);
 
                 list.add(container);
@@ -1426,7 +1411,7 @@
         // RT-20643
         CssError.setCurrentScene(parent.getScene());
 
-        final List<StylesheetContainer> list = processStylesheets(parentStylesheets, (c) -> c.parentUsers.add(parent));
+        final List<StylesheetContainer> list = processStylesheets(parentStylesheets, parent);
 
         // RT-20643
         CssError.setCurrentScene(null);
@@ -1452,7 +1437,7 @@
         // RT-20643
         CssError.setCurrentScene(scene);
 
-        final List<StylesheetContainer> list = processStylesheets(sceneStylesheets, (c) -> c.sceneUsers.add(scene));
+        final List<StylesheetContainer> list = processStylesheets(sceneStylesheets, scene.getRoot());
 
         // RT-20643
         CssError.setCurrentScene(null);
@@ -1532,7 +1517,7 @@
                 && hasSceneStylesheets == false
                 && hasSceneUserAgentStylesheet == false
                 && hasSubSceneUserAgentStylesheet == false
-                && userAgentStylesheetContainers.isEmpty()) {
+                && platformUserAgentStylesheetContainers.isEmpty()) {
             return StyleMap.EMPTY_MAP;
         }
 
@@ -1577,37 +1562,38 @@
                         subScene.getUserAgentStylesheet().trim() :
                         scene.getUserAgentStylesheet().trim();
 
-                final Integer index = userAgentStylesheets.computeIfAbsent(
-                        uaFileName,
-                        (fname) -> {
-                            final Integer size = Integer.valueOf(userAgentStylesheetContainers.size());
-                            final Stylesheet ss = loadStylesheet(fname);
-                            if (ss != null) {
-                                ss.setOrigin(StyleOrigin.USER_AGENT);
-                            }
-                            userAgentStylesheetContainers.add(new StylesheetContainer(fname, ss, new byte[0]));
-                            return size;
-                        }
-                );
-                final StylesheetContainer container = userAgentStylesheetContainers.get(index.intValue());
-                if (container != null && container.selectorPartitioning != null) {
+
+                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;
+                }
+
+                if (container == null) {
+                    Stylesheet stylesheet = loadStylesheet(uaFileName);
+                    if (stylesheet != null) {
+                        stylesheet.setOrigin(StyleOrigin.USER_AGENT);
+                    }
+                    container = new StylesheetContainer(uaFileName, stylesheet);
+                    userAgentStylesheetContainers.add(container);
+                }
+
+                if (container.selectorPartitioning != null) {
+
+                    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 (platformUserAgentStylesheets.isEmpty() == false) {
-                for(int n=0, nMax=platformUserAgentStylesheets.size(); n<nMax; n++) {
-                    final String uaFileName = platformUserAgentStylesheets.get(n).trim();
-                    final Integer index = userAgentStylesheets.get(uaFileName);
-                    if (index == null) {
-                        platformUserAgentStylesheets.remove(uaFileName);
-                        if (getLogger().isLoggable(Level.WARNING)) {
-                            getLogger().warning("user-agent stylesheet not indexed, removed from list: '" + uaFileName + "'");
-                        }
-                    }
-                    final StylesheetContainer container = userAgentStylesheetContainers.get(n);
-
+            } 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);
--- a/modules/graphics/src/main/java/javafx/scene/Scene.java	Fri May 02 17:19:28 2014 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/Scene.java	Fri May 02 17:33:21 2014 -0400
@@ -1513,7 +1513,7 @@
      * @see #getUserAgentStylesheet()
      * @see #setUserAgentStylesheet(String)
      */
-    public ObjectProperty<String> userAgentStylesheetProperty() {
+    public final ObjectProperty<String> userAgentStylesheetProperty() {
         if (userAgentStylesheet == null) {
             userAgentStylesheet = new SimpleObjectProperty<String>(Scene.this, "userAgentStylesheet", null) {
                 @Override protected void invalidated() {
@@ -1535,7 +1535,7 @@
      * @return The URL of the user-agent stylesheet that will be used by this Scene,
      * or null if has not been set.
      */
-    public String getUserAgentStylesheet() {
+    public final String getUserAgentStylesheet() {
         return userAgentStylesheet == null ? null : userAgentStylesheet.get();
     }
 
@@ -1552,7 +1552,7 @@
      * Any leading '/' character of the [path] is ignored and the [path] is treated as a path relative to
      * the root of the application's classpath.
      */
-    public void setUserAgentStylesheet(String url) {
+    public final void setUserAgentStylesheet(String url) {
         userAgentStylesheetProperty().set(url);
     }
 
--- a/modules/graphics/src/main/java/javafx/scene/SubScene.java	Fri May 02 17:19:28 2014 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/SubScene.java	Fri May 02 17:33:21 2014 -0400
@@ -240,7 +240,7 @@
                     _value.setDisabled(isDisabled());
 
                     if (oldRoot != null) {
-                        cssForget(StyleManager.getInstance(),oldRoot);
+                        StyleManager.getInstance().forget(SubScene.this);
                         oldRoot.setScenes(null, null);
                     }
                     oldRoot = _value;
@@ -583,11 +583,11 @@
      * @see #getUserAgentStylesheet()
      * @see #setUserAgentStylesheet(String)
      */
-    public ObjectProperty<String> userAgentStylesheetProperty() {
+    public final ObjectProperty<String> userAgentStylesheetProperty() {
         if (userAgentStylesheet == null) {
             userAgentStylesheet = new SimpleObjectProperty<String>(SubScene.this, "userAgentStylesheet", null) {
                 @Override protected void invalidated() {
-                    cssForget(StyleManager.getInstance(), getRoot());
+                    StyleManager.getInstance().forget(SubScene.this);
                     impl_reapplyCSS();
                 }
             };
@@ -595,19 +595,6 @@
         return userAgentStylesheet;
     }
 
-    private void cssForget(final StyleManager styleManager, final Parent parent) {
-
-        if (parent == null) return;
-        styleManager.forget(parent);
-
-        for(Node child : parent.getChildren()) {
-            if (child instanceof Parent) {
-                cssForget(styleManager, (Parent)child);
-            }
-        }
-
-     }
-
     /**
      * Get the URL of the user-agent stylesheet that will be used by this SubScene. If the URL has not been set,
      * the platform-default user-agent stylesheet will be used.
@@ -618,7 +605,7 @@
      * @return The URL of the user-agent stylesheet that will be used by this SubScene,
      * or null if has not been set.
      */
-    public String getUserAgentStylesheet() {
+    public final String getUserAgentStylesheet() {
         return userAgentStylesheet == null ? null : userAgentStylesheet.get();
     }
 
@@ -635,7 +622,7 @@
      * Any leading '/' character of the [path] is ignored and the [path] is treated as a path relative to
      * the root of the application's classpath.
      */
-    public void setUserAgentStylesheet(String url) {
+    public final void setUserAgentStylesheet(String url) {
         userAgentStylesheetProperty().set(url);
     }
 
--- a/modules/graphics/src/test/java/com/sun/javafx/css/StyleManagerTest.java	Fri May 02 17:19:28 2014 -0400
+++ b/modules/graphics/src/test/java/com/sun/javafx/css/StyleManagerTest.java	Fri May 02 17:33:21 2014 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,16 +25,21 @@
 
 package com.sun.javafx.css;
 
-import com.sun.javafx.pgstub.StubToolkit;
-import com.sun.javafx.tk.Toolkit;
+import com.sun.javafx.css.parser.CSSParser;
 import javafx.scene.Group;
+import javafx.scene.Parent;
 import javafx.scene.Scene;
+import javafx.scene.SubScene;
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
 import javafx.scene.shape.Rectangle;
-import javafx.scene.text.Text;
-import javafx.stage.Popup;
-import javafx.stage.Stage;
 import org.junit.Before;
 import org.junit.Test;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
 import static org.junit.Assert.*;
 
 /**
@@ -45,34 +50,15 @@
     
     public StyleManagerTest() {
     }
-    
+
     @Before
     public void setUp() {
-//        rect = new Rectangle();
-//        rect.setId("rectangle");
-//
-//        text = new Text();
-//        text.setId("text");
-//
-//        Group group = new Group();
-//        group.getChildren().addAll(rect, text);
-//
-//        scene = new Scene(group);/* {
-//            TestWindow window;
-//            {
-//                window = new TestWindow();
-//                window.setScene(HonorDeveloperSettingsTest.this.scene);
-//                impl_setWindow(window);
-//            }
-//        };*/
-//        
-//        System.setProperty("binary.css", "false");
-//        String url = getClass().getResource("HonorDeveloperSettingsTest_UA.css").toExternalForm();
-//        StyleManager.getInstance().setDefaultUserAgentStylesheet(url);
-//        
-//        Stage stage = new Stage();
-//        stage.setScene(scene);
-//        stage.show();
+        StyleManager sm = StyleManager.getInstance();
+        sm.userAgentStylesheetContainers.clear();
+        sm.platformUserAgentStylesheetContainers.clear();
+        sm.stylesheetContainerMap.clear();
+        sm.cacheContainerMap.clear();
+        sm.hasDefaultUserAgentStylesheet = false;
     }
     
     @Test
@@ -81,5 +67,761 @@
         StyleManager sm = StyleManager.getInstance();
         assertNotNull(sm);
     }
-        
+
+    private static int indexOf(final List<StyleManager.StylesheetContainer> list, final String fname) {
+
+        for (int n=0, nMax=list.size(); n<nMax; n++) {
+            StyleManager.StylesheetContainer container = list.get(n);
+            if (fname.equals(container.fname)) {
+                return n;
+            }
+        }
+
+        return -1;
+    }
+
+    @Test
+    public void testAddUserAgentStyleshseet_String() {
+        StyleManager sm = StyleManager.getInstance();
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+        int index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+    }
+
+    @Test
+    public void testAddUserAgentStyleshseet_String_Multiple() {
+        StyleManager sm = StyleManager.getInstance();
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua1.css");
+        assertEquals(1, index);
+    }
+
+    @Test
+    public void testAddUserAgentStyleshseet_String_Duplicate() {
+        StyleManager sm = StyleManager.getInstance();
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        assertTrue(sm.platformUserAgentStylesheetContainers.size() == 2);
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(1, index);
+
+    }
+
+    @Test
+    public void testSetDefaultUserAgentStyleshseet_String() {
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+    }
+
+    @Test
+    public void testSetUserAgentStyleshseet_String_Multiple() {
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        assertTrue(sm.platformUserAgentStylesheetContainers.size() == 2);
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua1.css");
+        assertEquals(1, index);
+    }
+
+    @Test
+    public void testSetUserAgentStyleshseet_String_Multiple2() {
+        StyleManager sm = StyleManager.getInstance();
+        // same as before but set default after adding another.
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        assertEquals(2, sm.platformUserAgentStylesheetContainers.size());
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(1, index);
+    }
+
+    @Test
+    public void testSetUserAgentStyleshseet_String_Duplicate() {
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+        sm.addUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        assertEquals(2, sm.platformUserAgentStylesheetContainers.size());
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua1.css");
+        assertEquals(1, index);
+    }
+
+    @Test
+    public void testAddUserAgentStyleshseet_Stylesheet() {
+
+        try {
+            StyleManager sm = StyleManager.getInstance();
+            URL ua0_url = StyleManagerTest.class.getResource("ua0.css");
+            Stylesheet stylesheet = CSSParser.getInstance().parse(ua0_url);
+            sm.addUserAgentStylesheet(null,stylesheet);
+
+            assertEquals(1, sm.platformUserAgentStylesheetContainers.size());
+
+            int index = indexOf(sm.platformUserAgentStylesheetContainers,ua0_url.toExternalForm());
+            assertEquals(0, index);
+
+        } catch (Exception ioe) {
+            fail(ioe.getMessage());
+        }
+
+    }
+
+    @Test
+    public void testSetDefaultUserAgentStyleshseet_Stylesheet() {
+
+        try {
+            StyleManager sm = StyleManager.getInstance();
+
+            URL ua1_url = StyleManagerTest.class.getResource("ua1.css");
+            Stylesheet stylesheet = CSSParser.getInstance().parse(ua1_url);
+            sm.addUserAgentStylesheet(null,stylesheet);
+
+            URL ua0_url = StyleManagerTest.class.getResource("ua0.css");
+            stylesheet = CSSParser.getInstance().parse(ua0_url);
+            sm.setDefaultUserAgentStylesheet(stylesheet);
+
+            assertEquals(2, sm.platformUserAgentStylesheetContainers.size());
+
+            int index = indexOf(sm.platformUserAgentStylesheetContainers,ua0_url.toExternalForm());
+            assertEquals(0, index);
+
+            index = indexOf(sm.platformUserAgentStylesheetContainers,ua1_url.toExternalForm());
+            assertEquals(1, index);
+
+        } catch (Exception ioe) {
+            fail(ioe.getMessage());
+        }
+
+    }
+
+    @Test
+    public void testSceneUAStylesheetAdded() {
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        // the Scene user-agent stylesheet is not a platform user-agent stylesheet
+        index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+    }
+
+    @Test
+    public void testSubSceneUAStylesheetAdded() {
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        // the Scene user-agent stylesheet is not a platform user-agent stylesheet
+        index = indexOf(sm.platformUserAgentStylesheetContainers, "/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+    }
+
+    @Test
+    public void testForgetParent() {
+
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        sm.forget(scene.getRoot());
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+    }
+
+    @Test
+    public void testForgetParent_withSceneUAStylesheet() {
+
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+//        sm.findMatchingStyles(scene.getRoot(), null, null);
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+        sm.forget(scene.getRoot());
+
+        // forgetting the parent should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        // only forgetting the scene should affect the platform user-agent stylesheets
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0, index);
+
+    }
+
+    @Test
+    public void testForgetParent_withTwoScenes() {
+        Scene scene0 = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene0.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        Scene scene1 = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene1.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        // even though there are two scenes using this stylesheet, there should only be one container.
+        assertEquals(1, sm.userAgentStylesheetContainers.size());
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+        sm.forget(scene0.getRoot());
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        // we should still have ua1.css since scene1 is still using it
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        sm.forget(scene1.getRoot());
+
+        // only forgetting the scene should affect the platform user-agent stylesheets
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0, index);
+    }
+
+    @Test
+    public void testForgetParent_withParentStylesheet() {
+
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene.getRoot().getStylesheets().add("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0, index);
+
+        assertTrue(sm.userAgentStylesheetContainers.isEmpty());
+        assertTrue(sm.stylesheetContainerMap.containsKey("/com/sun/javafx/css/ua1.css"));
+
+        sm.forget(scene.getRoot());
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0, index);
+
+        assertFalse(sm.stylesheetContainerMap.containsKey("/com/sun/javafx/css/ua1.css"));
+
+    }
+
+    @Test
+    public void testForgetParent_withMultipleParentStylesheets() {
+
+        final Parent parent0 = new Pane(new Rectangle(){{ getStyleClass().add("rect"); }});
+        parent0.getStylesheets().add("/com/sun/javafx/css/ua1.css");
+
+        final Parent parent1 = new Pane(new Rectangle(){{ getStyleClass().add("rect"); }});
+        parent1.getStylesheets().add("/com/sun/javafx/css/ua1.css");
+
+        Scene scene = new Scene(new Group(parent0, parent1));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        assertTrue(sm.userAgentStylesheetContainers.isEmpty());
+
+        StyleManager.StylesheetContainer container = sm.stylesheetContainerMap.get("/com/sun/javafx/css/ua1.css");
+        assertNotNull(container);
+        assertTrue(container.parentUsers.contains(parent0));
+        assertTrue(container.parentUsers.contains(parent1));
+
+        sm.forget(parent0);
+
+        assertTrue(sm.stylesheetContainerMap.containsKey("/com/sun/javafx/css/ua1.css"));
+        assertFalse(container.parentUsers.contains(parent0));
+        assertTrue(container.parentUsers.contains(parent1));
+
+        sm.forget(parent1);
+
+        assertFalse(sm.stylesheetContainerMap.containsKey("/com/sun/javafx/css/ua1.css"));
+        assertFalse(container.parentUsers.contains(parent0));
+        assertFalse(container.parentUsers.contains(parent1));
+    }
+
+    @Test
+    public void testForgetScene() {
+
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        sm.forget(scene);
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+    }
+
+    @Test
+    public void testForgetScene_withUAStylesheet() {
+
+        Scene scene = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+        sm.forget(scene);
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+    }
+
+    @Test
+    public void testForgetScene_withTwoScenes() {
+        Scene scene0 = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene0.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        Scene scene1 = new Scene(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        scene1.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        // even though there are two scenes using this stylesheet, there should only be one container.
+        assertEquals(1, sm.userAgentStylesheetContainers.size());
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+        sm.forget(scene0);
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        // we should still have ua1.css since scene1 is still using it
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        sm.forget(scene1);
+
+        // having forgotten scene1, userAgentStylesheetContainers should be empty.
+        assertTrue(sm.userAgentStylesheetContainers.isEmpty());
+    }
+
+    @Test
+    public void testForgetSubScene() {
+
+        Pane subSceneRoot = new Pane(new Rectangle(){{ getStyleClass().add("rect"); }});
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        sm.forget(subScene);
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+    }
+
+    @Test
+    public void testForgetSubScene_withUAStylesheet() {
+
+        Pane subSceneRoot = new Pane(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        subScene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+        sm.forget(subScene);
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+    }
+
+    @Test
+    public void testForgetSubScene_with_UAStylesheet_and_ParentStylesheet() {
+
+        // make sure forget(SubScene) get's children with stylesheets
+        Group group = new Group(new Rectangle(){{ getStyleClass().add("rect"); }});
+        group.getStylesheets().add("/com/sun/javafx/css/ua2.css");
+        Pane subSceneRoot = new Pane(group);
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        subScene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+        sm.forget(subScene);
+
+        // forgetting the scene should not affect the platform user-agent stylesheets
+        index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1, index);
+
+    }
+
+    @Test
+    public void testChangeSubSceneStylesheet() {
+
+        Pane subSceneRoot = new Pane(new Group(new Rectangle(){{ getStyleClass().add("rect"); }}));
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        int index = indexOf(sm.platformUserAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(0,index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua0.css");
+        assertEquals(-1, index);
+
+        subScene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(0,index);
+
+        sm.forget(subScene);
+
+        subScene.setUserAgentStylesheet("/com/sun/javafx/css/ua2.css");
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua2.css");
+        assertEquals(0, index);
+
+        index = indexOf(sm.userAgentStylesheetContainers,"/com/sun/javafx/css/ua1.css");
+        assertEquals(-1,index);
+
+    }
+
+    @Test
+    public void testFindMatchingStyles_defaultStyleSheet() {
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        Rectangle rect = new Rectangle(){{ getStyleClass().add("rect"); }};
+        Scene scene = new Scene(new Group(rect));
+
+        StyleMap matchingStyles = sm.findMatchingStyles(rect, null, null);
+        Map<String,List<CascadingStyle>> styleMap = matchingStyles.getCascadingStyles();
+
+        assertTrue(styleMap.containsKey("-fx-fill"));
+
+        List<CascadingStyle> styles = styleMap.get("-fx-fill");
+        assertEquals(1, styles.size());
+
+        Object obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.RED, obj);
+    }
+
+    @Test
+    public void testFindMatchingStyles_defaultStyleSheet_sceneUserAgentStylesheet() {
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        Rectangle rect = new Rectangle(){{ getStyleClass().add("rect"); }};
+        Scene scene = new Scene(new Group(rect));
+        scene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        StyleMap matchingStyles = sm.findMatchingStyles(rect, null, null);
+        Map<String,List<CascadingStyle>> styleMap = matchingStyles.getCascadingStyles();
+
+        // scene stylesheet should totally replace default
+        assertFalse(styleMap.containsKey("-fx-fill"));
+        assertTrue(styleMap.containsKey("-fx-stroke"));
+
+        List<CascadingStyle> styles = styleMap.get("-fx-stroke");
+        assertEquals(1, styles.size());
+
+        Object obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.YELLOW, obj);
+    }
+
+    @Test
+    public void testFindMatchingStyles_defaultStyleSheet_sceneUserAgentStylesheet_sceneAuthorStylesheet() {
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        Rectangle rect = new Rectangle(){{ getStyleClass().add("rect"); }};
+        Scene scene = new Scene(new Group(rect));
+        scene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        scene.getStylesheets().add("/com/sun/javafx/css/ua2.css");
+
+        StyleMap matchingStyles = sm.findMatchingStyles(rect, null, null);
+        Map<String,List<CascadingStyle>> styleMap = matchingStyles.getCascadingStyles();
+
+        // ua2.css has fill
+        assertTrue(styleMap.containsKey("-fx-fill"));
+        assertTrue(styleMap.containsKey("-fx-stroke"));
+
+        // ua1.css and ua2.css have stroke
+        List<CascadingStyle> styles = styleMap.get("-fx-stroke");
+        assertEquals(2, styles.size());
+
+        Object obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.GREEN, obj);
+
+        // ua0.css and ua2.css have fill, but we shouldn't get anything from ua0
+        // since we have a scene user-agent stylesheet
+        styles = styleMap.get("-fx-fill");
+        assertEquals(1, styles.size());
+
+        obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.BLUE, obj);
+    }
+
+    @Test
+    public void testFindMatchingStyles_defaultStyleSheet_subSceneUserAgentStylesheet() {
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        Rectangle rect = new Rectangle(){{ getStyleClass().add("rect"); }};
+        Pane subSceneRoot = new Pane(rect);
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        subScene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleMap matchingStyles = sm.findMatchingStyles(rect, subScene, null);
+        Map<String,List<CascadingStyle>> styleMap = matchingStyles.getCascadingStyles();
+
+        // SubScene stylesheet should totally replace default
+        assertFalse(styleMap.containsKey("-fx-fill"));
+        assertTrue(styleMap.containsKey("-fx-stroke"));
+
+        List<CascadingStyle> styles = styleMap.get("-fx-stroke");
+        assertEquals(1, styles.size());
+
+        Object obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.YELLOW, obj);
+    }
+
+    @Test
+    public void testFindMatchingStyles_defaultStyleSheet_subSceneUserAgentStylesheet_parentStylesheet() {
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        Rectangle rect = new Rectangle(){{ getStyleClass().add("rect"); }};
+        Group group = new Group(rect);
+        group.getStylesheets().add("/com/sun/javafx/css/ua2.css");
+        Pane subSceneRoot = new Pane(group);
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        subScene.setUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleMap matchingStyles = sm.findMatchingStyles(rect, subScene, null);
+        Map<String,List<CascadingStyle>> styleMap = matchingStyles.getCascadingStyles();
+
+        // ua2.css has fill
+        assertTrue(styleMap.containsKey("-fx-fill"));
+        assertTrue(styleMap.containsKey("-fx-stroke"));
+
+        // ua1.css and ua2.css have stroke
+        List<CascadingStyle> styles = styleMap.get("-fx-stroke");
+        assertEquals(2, styles.size());
+
+        Object obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.GREEN, obj);
+
+        // ua0.css and ua2.css have fill, but we shouldn't get anything from ua0
+        // since we have a scene user-agent stylesheet
+        styles = styleMap.get("-fx-fill");
+        assertEquals(1, styles.size());
+
+        obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.BLUE, obj);
+    }
+
+    @Test
+    public void testSwitchDefaultUserAgentStylesheets() {
+
+        Rectangle rect = new Rectangle(){{ getStyleClass().add("rect"); }};
+        Group group = new Group(rect);
+        Pane subSceneRoot = new Pane(group);
+        SubScene subScene = new SubScene(subSceneRoot, 100, 100);
+        Scene scene = new Scene(new Group(subScene));
+
+        StyleManager sm = StyleManager.getInstance();
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua0.css");
+
+        StyleMap matchingStyles = sm.findMatchingStyles(rect, subScene, null);
+        Map<String,List<CascadingStyle>> styleMap = matchingStyles.getCascadingStyles();
+
+        // ua0.css has fill
+        assertTrue(styleMap.containsKey("-fx-fill"));
+        assertFalse(styleMap.containsKey("-fx-stroke"));
+
+        List<CascadingStyle> styles = styleMap.get("-fx-fill");
+        assertEquals(1, styles.size());
+
+        Object obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.RED, obj);
+
+        sm.setDefaultUserAgentStylesheet("/com/sun/javafx/css/ua1.css");
+
+        matchingStyles = sm.findMatchingStyles(rect, subScene, null);
+        styleMap = matchingStyles.getCascadingStyles();
+
+        // ua1.css has  stroke
+        assertTrue(styleMap.containsKey("-fx-stroke"));
+        assertFalse(styleMap.containsKey("-fx-fill"));
+
+        styles = styleMap.get("-fx-stroke");
+        assertEquals(1, styles.size());
+
+        obj = styles.get(0).getParsedValueImpl().convert(null);
+        assertEquals(Color.YELLOW, obj);
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/test/resources/com/sun/javafx/css/ua0.css	Fri May 02 17:33:21 2014 -0400
@@ -0,0 +1,1 @@
+.rect { -fx-fill: red; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/test/resources/com/sun/javafx/css/ua1.css	Fri May 02 17:33:21 2014 -0400
@@ -0,0 +1,1 @@
+.rect { -fx-stroke: yellow; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/test/resources/com/sun/javafx/css/ua2.css	Fri May 02 17:33:21 2014 -0400
@@ -0,0 +1,1 @@
+.rect { -fx-stroke: green; -fx-fill: blue; }