changeset 1761:e76f959dbc62

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/MASTER/rt
author leifs
date Fri, 14 Sep 2012 10:20:59 -0700
parents 49758b2a4097 6b6962fcc056
children 28c8728cb18c
files javafx-ui-common/src/javafx/scene/Node.java
diffstat 21 files changed, 1563 insertions(+), 883 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/nbproject/project.xml	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/nbproject/project.xml	Fri Sep 14 10:20:59 2012 -0700
@@ -74,6 +74,19 @@
                         </arity>
                     </context>
                 </action>
+                <action name="run.single">
+                    <script>nbproject/ide-file-targets.xml</script>
+                    <target>run-selected-file-in-src</target>
+                    <context>
+                        <property>run.class</property>
+                        <folder>${src.dir}</folder>
+                        <pattern>\.java$</pattern>
+                        <format>java-name</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
             </ide-actions>
             <export>
                 <type>jar</type>
--- a/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Fri Sep 14 10:20:59 2012 -0700
@@ -192,11 +192,6 @@
     }
 
     @Override
-    boolean mightApply(final String className, final String id, final List<String> styleClasses) {
-        return selectors.get(selectors.size()-1).mightApply(className, id, styleClasses);
-    }
-
-    @Override
     boolean stateMatches(final Node node, long states) {
         return stateMatches(node, states, selectors.size()-1);
     }
--- a/javafx-ui-common/src/com/sun/javafx/css/ParentStyleManager.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/ParentStyleManager.java	Fri Sep 14 10:20:59 2012 -0700
@@ -31,7 +31,6 @@
 import javafx.scene.Scene;
 
 import javafx.collections.ListChangeListener.Change;
-import javafx.scene.Node;
 import javafx.scene.Parent;
 
 /**
@@ -47,22 +46,12 @@
 
         super(parent);
         this.ancestorStyleManager = ancestorStyleManager;
-        this.key = new ParentKey();
-        this.indices = getIndicesOfParentsWithStylesheets(parent, 0);
         updateStylesheets();
     }
 
     /** Either the Scene styleManager or the styleManager of a Parent */
     private final StyleManager ancestorStyleManager;
-    
-    /**
-     * This instance is reused for each lookup in the cache so as to avoid
-     * creating temporary objects as much as reasonable.
-     */
-    private final ParentKey key;    
-    
-    private final int[] indices;
-    
+        
     /**
      * Another map from String => Stylesheet for a Parent. If a stylesheet for the 
      * given URL has already been loaded then we'll simply reuse the stylesheet
@@ -78,28 +67,16 @@
     ////////////////////////////////////////////////////////////////////////////
     
     @Override
-    public void updateStylesheets() {
-        // The list of referenced stylesheets is about to be recalculated, 
-        // so clear the current list. The style maps are no longer valid, so
-        // annihilate the cache
-        referencedStylesheets.clear();
-        clearCache();
-
-        if (defaultUserAgentStylesheet != null) {
-            referencedStylesheets.add(defaultUserAgentStylesheet);
-        }
-        
-        if (userAgentStylesheetMap.isEmpty() == false) {
-            // TODO: This isn't right. They should be in the same order that
-            // they were first added.
-            referencedStylesheets.addAll(userAgentStylesheetMap.values());
-        }
+    protected void updateStylesheetsImpl() {
         
         referencedStylesheets.addAll(ancestorStyleManager.referencedStylesheets);
         
         // RT-20643
-        CssError.setCurrentScene(owner.getScene());
-
+        CssError.setCurrentScene(owner.getScene());        
+        
+        // RT-20643
+        CssError.setCurrentScene(null);                
+        
         // create the stylesheets, one per URL supplied
         List<String> stylesheetURLs = owner.getStylesheets();
         
@@ -133,21 +110,6 @@
         
     }
     
-    @Override
-    protected Key getKey(Node node) {
-        
-        // Populate our helper key with the class name, id, and style class
-        // of the node and lookup the associated Cache in the cacheMap
-        key.className = node.getClass().getName();
-        key.id = node.getId();
-        key.styleClass = node.getStyleClass();
-
-        key.indices = indices;
-        
-        return key;
-        
-    }
-
     ////////////////////////////////////////////////////////////////////////////
     //
     // Parent stylesheet handling
@@ -209,7 +171,7 @@
     private void clearParentCache(StylesheetContainer<Parent> psc) {
 
         final List<Reference<Parent>> parentList = psc.users.list;
-        final List<Reference<StyleManager.Key>>    keyList    = psc.keys.list;
+        final List<Reference<SimpleSelector>>    keyList    = psc.keys.list;
         for (int n=parentList.size()-1; 0<=n; --n) {
 
             final Reference<Parent> ref = parentList.get(n);
@@ -230,14 +192,14 @@
     }
 
     // RT-22565: Called from clearParentCache to clear the cache entries.
-    private void clearParentCache(List<Reference<StyleManager.Key>> keyList) {
+    private void clearParentCache(List<Reference<SimpleSelector>> keyList) {
 
         if (cacheMap.isEmpty()) return;
 
         for (int n=keyList.size()-1; 0<=n; --n) {
 
-            final Reference<StyleManager.Key> ref = keyList.get(n);
-            final StyleManager.Key key = ref.get();
+            final Reference<SimpleSelector> ref = keyList.get(n);
+            final SimpleSelector key = ref.get();
             if (key == null) continue;
 
             final StyleManager.Cache cache = cacheMap.remove(key);
@@ -309,91 +271,5 @@
 
         return stylesheet;
     }
-    
-    
-    /**
-     * The key used in the cacheMap of the StylesheetContainer
-     */
-    private static class ParentKey extends StyleManager.Key {
-        
-        ParentKey() {
-            super();
-            indices = null;
-        }
-
-        protected Key dup() {
             
-            ParentKey key = new ParentKey();
-            key.className  = className;
-            key.id = id;
-            final int nElements = styleClass.size();
-            key.styleClass = new ArrayList<String>(nElements);
-            for (int n = 0; n < nElements; n++) {
-                key.styleClass.add(styleClass.get(n));
-            }
-            key.indices = indices;
-            
-            return key;
-        }
-        
-        // this will be initialized if a Parent has a stylesheet and will
-        // hold the indices of those Parents with stylesheets (the Parent's
-        // hash code is used). If the parent does not have a stylesheet, the
-        // indice will be -1. When finding the equals Key in the cache lookup,
-        // we only need to check up to the last parent that has a stylesheet.
-        // In other words, if one node is at level n and nearest parent with
-        // a stylesheet is at level m, then the indices match provided
-        // indices[x] == other.indices[x] for 0 <= x <= m and all other
-        // indices are -1. Thus, [1, -1, 2] and [1, -1, 2, -1, -1] are equivalent
-        // whereas [1, -1, 2] and [1, -1, 2, -1, 3] are not.
-        private int[] indices;
-
-        public int[] getIndices() {
-            return indices;
-        }
-
-        public void setIndices(int[] indices) {
-            this.indices = indices;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o instanceof ParentKey && super.equals(o)) {
-                ParentKey other = (ParentKey)o;
-                if(indices != null && other.indices != null) {
-                    boolean eq = true;
-                    final int max = Math.min(indices.length, other.indices.length);
-                    for (int x = 0; eq && (x < max); x++) {
-                        eq = indices[x] == other.indices[x];
-                    }
-                    if (eq) {
-                        // ensure the remainder are -1
-                        for(int x=max; eq && x<indices.length; x++) {
-                            eq = indices[x] == -1;
-                        }
-                        for(int x=max; eq && x<other.indices.length; x++) {
-                            eq = other.indices[x] == -1;
-                        }
-                    }
-                    return eq;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = super.hashCode();
-            if (indices != null) hash = 31 * (hash + Arrays.hashCode(indices));
-            return hash;
-        }
-
-        @Override
-        public String toString() {
-            final String istr = indices != null ? Arrays.toString(indices) : "[]";
-            return "ParentKey {"+className+", "+id+", "+String.valueOf(styleClass)+", "+istr+"}";
-        }
-
-    }
-    
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Fri Sep 14 10:20:59 2012 -0700
@@ -115,7 +115,10 @@
         List<Match> matches = new ArrayList<Match>();
         for (int i = 0; i < selectors.size(); i++) {
             Selector sel = selectors.get(i);
-            matches.add(sel.matches(node));
+            Match match = sel.matches(node);
+            if (match != null) {
+                matches.add(match);
+            }
         }
         return matches;
     }
@@ -124,19 +127,14 @@
         List<Match> matches = new ArrayList<Match>();
         for (int i = 0; i < selectors.size(); i++) {
             Selector sel = selectors.get(i);
-            matches.add(sel.matches(scene));
+            Match match = sel.matches(scene);
+            if (match != null) {
+                matches.add(match);
+            }
         }
         return matches;
     }
 
-    public boolean mightApply(String className, String id, List<String> styleClasses) {
-        for (int i = 0; i < selectors.size(); i++) {
-            Selector sel = selectors.get(i);
-            if (sel.mightApply(className, id, styleClasses)) return true;
-        }
-        return false;
-    }
-
     public boolean applies(Node node) {
         for (int i = 0; i < selectors.size(); i++) {
             Selector sel = selectors.get(i);
--- a/javafx-ui-common/src/com/sun/javafx/css/SceneStyleManager.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/SceneStyleManager.java	Fri Sep 14 10:20:59 2012 -0700
@@ -54,8 +54,6 @@
 
         this.popupOwnerScene = scene;
         
-        this.key = new StyleManager.Key();
-        
         // We have special handling for the case of a node which is in a popup
         // scene. The problem is that the root scene used for the purpose of style
         // sheet support isn't the scene of the popup (which is a hidden API
@@ -137,8 +135,6 @@
         
     }
 
-    private final StyleManager.Key key;
-    
     /*
      * In the case of a popup, this is the Scene of the ownerWindow. If
      * the Scene's window is not a PopupWindow, then the rootScene == scene.
@@ -173,24 +169,9 @@
      *
      * @param scene     The scene to update stylesheets for
      */
-    public void updateStylesheets() {
-        
-        // The list of referenced stylesheets is about to be recalculated, 
-        // so clear the current list. The style maps are no longer valid, so
-        // annihilate the cache
-        referencedStylesheets.clear();
-        clearCache();
-
-        if (defaultUserAgentStylesheet != null) {
-            referencedStylesheets.add(defaultUserAgentStylesheet);
-        }
-        
-        if (userAgentStylesheetMap.isEmpty() == false) {
-            // TODO: This isn't right. They should be in the same order that
-            // they were first added.
-            referencedStylesheets.addAll(userAgentStylesheetMap.values());
-        }
-        
+    @Override
+    protected void updateStylesheetsImpl() {
+                
         // RT-20643
         CssError.setCurrentScene(owner);
 
@@ -241,29 +222,14 @@
                     container = new StylesheetContainer<Scene>(url, stylesheet);
                     container.users.add(owner);
                     if (stylesheet != null) {
-                        referencedStylesheets.add(stylesheet); 
-                    }
+                        referencedStylesheets.add(stylesheet);
+                   }
                     
                 }
             }
+            
         }
                             
-        // RT-20643
-        CssError.setCurrentScene(null);
-            
-    }
+   }
     
-    @Override
-    protected Key getKey(Node node) {
-        
-        // Populate our helper key with the class name, id, and style class
-        // of the node and lookup the associated Cache in the cacheMap
-        key.className = node.getClass().getName();
-        key.id = node.getId();
-        key.styleClass = node.getStyleClass();
-
-        return key;
-        
-    }
-
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Fri Sep 14 10:20:59 2012 -0700
@@ -62,7 +62,7 @@
     abstract Match matches(Scene scene);
     // same as the matches method expect return true/false rather than a match
     public abstract boolean applies(Node node);
-    abstract boolean mightApply(String className, String id, List<String> styleClasses);
+    
     /**
      * Determines whether the current state of the node and its parents
      * matches the pseudoclasses defined (if any) for this selector.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/css/SelectorPartitioning.java	Fri Sep 14 10:20:59 2012 -0700
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.css;
+
+import java.lang.reflect.Array;
+import java.util.*;
+
+/**
+ * Code to partition selectors into a tree-like structure for faster matching.
+ */
+public final class SelectorPartitioning {
+
+    /** package accessible */
+    SelectorPartitioning() {}
+    
+    /*
+     * SimpleSelector uses long[] for StyleClass. This wraps the long[]
+     * so that it can be used as a key in the selector maps.
+    */
+    private final static class StyleClassKey {
+        
+        private final long[] bits;
+        private final static long[] EMPTY_BITS = new long[0];
+        private final static StyleClassKey WILDCARD = new StyleClassKey(EMPTY_BITS);
+        
+        private StyleClassKey(long[] bits) {
+            this.bits = (bits != null) ? new long[bits.length] : EMPTY_BITS;
+            System.arraycopy(bits, 0, this.bits, 0, bits.length);
+        }
+        
+        /*
+         * Test that all the bits of this key are present in the other. Given
+         * <pre>
+         * {@code
+         * Key k1 = new Key(0x5);
+         * Key k2 = new Key(0x4);}</pre> {@code k1.isSubset(k2) } returns false
+         * and {@code k2.isSubset(k1) } returns true; <p> Note that one cannot
+         * assume if {@code x.isSubsetOf(y) == false }
+         * that {@code y.isSuperSetOf(x) == true } since <i>x</i> and <i>y</i>
+         * might be disjoint.
+         *
+         * @return true if this Key is a subset of the other.
+         */
+        private boolean isSubsetOf(StyleClassKey other) {
+        
+            // they are a subset if both are empty
+            if (bits.length == 0 && other.bits.length == 0) return true;
+
+            // [foo bar] cannot be a subset of [foo]
+            if (bits.length > other.bits.length) return false;
+
+            // is [foo bar] a subset of [foo bar bang]?
+            for (int n=0, max=bits.length; n<max; n++) {
+                if ((bits[n] & other.bits[n]) != bits[n]) return false;
+            }
+            return true;
+
+        }
+
+        /*
+         * return true if this seq1 is a superset of seq2. That is to say
+         * that all the bits seq2 of the other key are present in seq1. Given
+         * <pre>
+         * {@code
+         * Key k1 = new Key(0x5);
+         * Key k2 = new Key(0x4);}</pre> {@code k1.isSupersetOf(k2) } returns
+         * true and {@code k2.isSupersetOf(k1) } returns false <p> Note that one
+         * cannot assume if {@code x.isSubsetOf(y) == false }
+         * that {@code y.isSuperSetOf(x) == true } since <i>x</i> and <i>y</i>
+         * might be disjoint.
+         */
+        private boolean isSupersetOf(StyleClassKey other) {
+            
+            // [foo] cannot be a superset of [foo  bar]
+            // nor can [foo] be a superset of [foo]
+            if (bits.length < other.bits.length) return false;
+
+            // is [foo bar bang] a superset of [foo bar]?
+            for (int n=0, max=other.bits.length; n<max; n++) {
+                if ((bits[n] & other.bits[n]) != other.bits[n]) return false;
+            }
+            return true;
+
+        }
+        
+        //
+        // Need hashCode since StyleClassKey is used as a key in a Map.
+        // 
+        @Override
+        public int hashCode() {
+            int hash = 7;
+            hash = 41 * hash + Arrays.hashCode(this.bits);
+            return hash;
+        }
+
+        //
+        // Need equals since StyleClassKey is used as a key in a Map.
+        // 
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final StyleClassKey other = (StyleClassKey) obj;
+            if (!Arrays.equals(this.bits, other.bits)) {
+                return false;
+            }
+            return true;
+        }
+        
+    }
+    
+    /*
+     * Wrapper so that we can have Map<ParitionKey, Partition> even though
+     * the innards of the key might be a String or long[]
+     */
+    private final static class PartitionKey<K> {
+    
+        private final K key;
+        
+        private PartitionKey(K key) {
+            this.key = key;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final PartitionKey<K> other = (PartitionKey<K>) obj;
+            if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 7;
+            hash = 71 * hash + (this.key != null ? this.key.hashCode() : 0);
+            return hash;
+        }                
+        
+    }   
+    
+    /** 
+     * Since Rules are retrieved from the tree in an indeterminate manner,
+     * we need to keep track of the order in which the rule was added. This
+     * can't be kept in Rule itself since the order depends on both the
+     * order of the stylesheets and the order of the rules in the stylesheets.
+     * Also, rules can be added and removed from the stylesheet which would
+     * invalidate the order.
+     */
+    private static class RuleData implements Comparable {
+        final Rule rule;
+        final int ordinal;
+        
+        private RuleData(Rule rule, int ordinal) {
+            this.rule = rule;
+            this.ordinal = ordinal;
+        }
+
+        @Override
+        public int compareTo(Object t) {
+            return ordinal - ((RuleData)t).ordinal;
+        }
+    }
+    
+    /**
+     * A Partition corresponds to a selector type, id or styleclass. For any
+     * given id (for example) there will be one Partition held in the
+     * corresponding map (idMap, for example). Each Partition has Slots which
+     * define a path from one Partition to the next. For example, if we have
+     * A.b#c, there will be a Partition for each of A, .b and #c. The partition
+     * for #c will have a Slot pointing to A. Likewise, A will have a Slot
+     * corresponding to .b. Each Slot is capable of pointing to more than one
+     * Partition. If another selector A.#c.z were partitioned, then the Slot
+     * for A in Partition #c would now have Slots for both .b and .z.
+     * <p> 
+     * Rules are added to the last Slot or to the Partition. If there is a 
+     * rule #c { -fx-fill: red; }, then the rule will be added to the
+     * Partition for #c. If the rule were for A.b#c, then rule would be added
+     * to the slot for '.b' which is in the slot for A in partion #c. 
+     * <p>
+     * When Node is matched, it picks up the Rules from the Partition and Slot 
+     * as the graph is traversed. 
+     */
+    private static final class Partition {
+        
+        private final PartitionKey key;
+        private final Map<PartitionKey, Slot> slots;
+        private List<RuleData> rules;
+        
+        private Partition(PartitionKey key) {
+           this.key = key;
+            slots = new HashMap<PartitionKey,Slot>();
+        }
+        
+        private void addRule(Rule rule, int ordinal) {
+            if (rules == null) {
+                rules = new ArrayList<RuleData>();
+            }
+            rules.add(new RuleData(rule,ordinal));
+        }
+        
+        private void copyRules(List<RuleData> to) {
+            if (rules != null && rules.isEmpty() == false) {
+                to.addAll(rules);
+            }
+        }
+        
+        /**   
+         * This routine finds the slot corresponding to the PartitionKey, 
+         * creating a Partition and Slot if necessary. 
+         */
+        private Slot partition(PartitionKey id, Map<PartitionKey, Partition> map) {
+            
+            Slot slot = slots.get(id);
+            if (slot == null) {
+                Partition partition = getPartition(id,map);
+                slot = new Slot(partition);
+                slots.put(id, slot);
+            }
+            return slot;
+        }
+        
+    }
+             
+    /**
+     * A Slot is pointer to the next piece of the selector.
+     */
+    private static final class Slot {
+
+
+        // The Partition to which this Slot belongs
+        private final Partition partition;
+
+        // The other Slots to which this Slot refers
+        private final Map<PartitionKey, Slot> referents;
+
+        // Rules from selectors that matches the path to this slot
+        private List<RuleData> rules;
+        
+        private Slot(Partition partition) {
+            this.partition = partition;
+            this.referents = new HashMap<PartitionKey, Slot>();            
+        }
+        
+        private void addRule(Rule rule, int ordinal) {
+            if (rules == null) {
+                rules = new ArrayList<RuleData>();
+            }
+            rules.add(new RuleData(rule,ordinal));
+        }
+        
+        private void copyRules(List<RuleData> to) {
+            if (rules != null && rules.isEmpty() == false) {
+                to.addAll(rules);
+            }
+            partition.copyRules(to);
+        }
+                     
+        /**   
+         * This routine finds the slot corresponding to the PartitionKey, 
+         * creating a Partition and Slot if necessary. 
+         */
+        private Slot partition(PartitionKey id, Map<PartitionKey, Partition> map) {
+            Slot slot = referents.get(id);
+            if (slot == null) {
+                
+                Partition p = getPartition(id, map);
+                slot = new Slot(p);
+                referents.put(id, slot);
+                
+            }
+            return slot;
+        }
+        
+    }
+
+    /* A Map for selectors that have an id */
+    private Map<PartitionKey, Partition> idMap = new HashMap<PartitionKey,Partition>();
+    
+    /* A Map for selectors that have an element type */
+    private Map<PartitionKey, Partition> typeMap = new HashMap<PartitionKey,Partition>();
+    
+    /* A Map for selectors that have style classes */
+    private Map<PartitionKey, Partition> styleClassMap = new HashMap<PartitionKey,Partition>();
+
+    /** 
+     * Keep track of the order in which a rule is added to the mapping so
+     * the original order can be restored for the cascade.
+     */
+    private int ordinal;
+    
+    /** clear current partitioning */
+    void reset() {
+        idMap.clear();
+        typeMap.clear();
+        styleClassMap.clear();
+        ordinal = 0;
+    }
+    
+    
+    /** 
+     * Helper to lookup an id in the given map, creating and adding a Partition
+     * 
+     */
+    private static Partition getPartition(PartitionKey id, Map<PartitionKey,Partition> map) {
+        
+        Partition treeNode = map.get(id);
+        if (treeNode == null) {
+            treeNode = new Partition(id);
+            map.put(id, treeNode);
+        }
+        return treeNode;
+    }
+
+    /* Mask that indicates the selector has an id part, e.g. #title */
+    private static final int ID_BIT = 4;
+    /* Mask that indicates the selector has a type part, e.g. Label */
+    private static final int TYPE_BIT = 2;
+    /* Mask that indicates the selector has a styleclass part, e.g. .label */
+    private static final int STYLECLASS_BIT = 1;
+    /* If there is no type part, then * is the default. */
+    private static final PartitionKey WILDCARD = new PartitionKey<String>("*");
+    
+    /* Place this selector into the partitioning map. Package accessible */
+    void partition(Selector selector, Rule rule) {
+        
+        SimpleSelector simpleSelector = null;
+        if (selector instanceof CompoundSelector) {
+            final List<SimpleSelector> selectors = ((CompoundSelector)selector).getSelectors();
+            final int last = selectors.size()-1;
+            simpleSelector = selectors.get(last);
+        } else {
+            simpleSelector = (SimpleSelector)selector;
+        }
+
+        final String selectorId = simpleSelector.getId();
+        final boolean hasId = 
+            (selectorId != null && selectorId.isEmpty() == false);
+        final PartitionKey idKey = hasId
+                ? new PartitionKey(selectorId)
+                : null;
+                
+        final String selectorType = simpleSelector.getName();
+        final boolean hasType = 
+            (selectorType != null && selectorType.isEmpty() == false);
+        final PartitionKey typeKey = hasType
+                ? new PartitionKey(selectorType)
+                : null;
+        
+        final long[] selectorStyleClass = simpleSelector.getStyleClassMasks();
+        final boolean hasStyleClass = 
+            (selectorStyleClass != null && selectorStyleClass.length > 0);
+        final PartitionKey styleClassKey = hasStyleClass 
+                ? new PartitionKey<StyleClassKey>(new StyleClassKey(selectorStyleClass))
+                : null;
+        
+        final int c = 
+            (hasId ? ID_BIT : 0) | (hasType ? TYPE_BIT : 0) | (hasStyleClass ? STYLECLASS_BIT : 0);
+
+        Partition partition = null;
+        Slot slot = null;
+
+        switch(c) {
+            case ID_BIT | TYPE_BIT | STYLECLASS_BIT: 
+            case ID_BIT | TYPE_BIT: 
+                
+                partition = getPartition(idKey, idMap);
+                slot = partition.partition(typeKey, typeMap);
+                if ((c & STYLECLASS_BIT) == STYLECLASS_BIT) {
+                    slot = slot.partition(styleClassKey, styleClassMap);
+                }                
+                slot.addRule(rule, ordinal++);
+                break;
+                
+            case TYPE_BIT | STYLECLASS_BIT:
+            case TYPE_BIT: 
+                
+                partition = getPartition(typeKey, typeMap);
+                if ((c & STYLECLASS_BIT) == STYLECLASS_BIT) {
+                    slot = partition.partition(styleClassKey, styleClassMap);
+                    slot.addRule(rule, ordinal++);
+                } else {
+                    partition.addRule(rule, ordinal++);                    
+                }
+                break;
+                
+            // SimpleSelector always has a type which defaults to '*'
+            case ID_BIT | STYLECLASS_BIT:                 
+            case ID_BIT: 
+            case STYLECLASS_BIT: 
+            default:
+                assert(false);
+        }
+        
+    }
+    
+    /** Get the list of rules that match this selector. Package accessible */
+    List<Rule> match(String selectorId, String selectorType, long[] selectorStyleClass) {
+        
+        final boolean hasId = 
+            (selectorId != null && selectorId.isEmpty() == false);
+        final PartitionKey idKey = hasId
+                ? new PartitionKey(selectorId)
+                : null;
+                
+        final boolean hasType = 
+            (selectorType != null && selectorType.isEmpty() == false);
+        final PartitionKey typeKey = hasType
+                ? new PartitionKey(selectorType)
+                : null;
+        
+        final boolean hasStyleClass = 
+            (selectorStyleClass != null && selectorStyleClass.length > 0);
+        final PartitionKey styleClassKey = hasStyleClass 
+                ? new PartitionKey<StyleClassKey>(new StyleClassKey(selectorStyleClass))
+                : null;
+        
+        int c = 
+            (hasId ? ID_BIT : 0) | (hasType ? TYPE_BIT : 0) | (hasStyleClass ? STYLECLASS_BIT : 0);
+
+        Partition partition = null;
+        Slot slot = null;
+        List<RuleData> ruleData = new ArrayList<RuleData>();
+        
+        while (c != 0) {
+            
+            switch(c) {
+                case ID_BIT | TYPE_BIT | STYLECLASS_BIT: 
+                case ID_BIT | TYPE_BIT: 
+                {
+
+                    partition = idMap.get(idKey);
+                    if (partition != null) {
+                        partition.copyRules(ruleData);
+
+                        // do-while handles A.b#c also matches A#c by first
+                        // doing A.b#c then doing *.b#c
+                        PartitionKey typePK = typeKey;
+                        do {
+                            slot = partition.slots.get(typePK);                    
+                            if (slot != null) {
+
+                                slot.copyRules(ruleData);
+
+                                if ((c & STYLECLASS_BIT) == STYLECLASS_BIT) {
+                                    StyleClassKey key = (StyleClassKey)styleClassKey.key;
+                                    for (Slot s : slot.referents.values()) {
+                                        StyleClassKey other = (StyleClassKey)s.partition.key.key;
+                                        if (other.isSubsetOf(key)) {
+                                            s.copyRules(ruleData);
+                                        }
+                                    }
+                                }
+                                
+                            }
+                            // if typePK is 'A', make it '*', if it is '*' make it null
+                            typePK=WILDCARD.equals(typePK) == false ? WILDCARD : null;
+
+                        } while(typePK != null);
+                    }
+                    
+                    c -= ID_BIT;
+                    continue;
+                }
+                    
+
+                // SimpleSelector always has a type which defaults to '*'
+                case ID_BIT | STYLECLASS_BIT: 
+                case ID_BIT: 
+                    c -= ID_BIT;
+                    break;
+                                        
+                case TYPE_BIT | STYLECLASS_BIT: 
+                case TYPE_BIT: 
+                {
+
+                    // do-while handles A.b also matches .b by first
+                    // doing A.b then doing *.b
+                    PartitionKey typePK = typeKey;
+                    do {
+                        partition = typeMap.get(typePK);
+                        if (partition != null) {
+                            partition.copyRules(ruleData);
+
+                            if ((c & STYLECLASS_BIT) == STYLECLASS_BIT) {
+                                StyleClassKey key = (StyleClassKey)styleClassKey.key;
+                                for (Slot s : partition.slots.values()) {
+                                    StyleClassKey other = (StyleClassKey)s.partition.key.key;
+                                    if (other.isSubsetOf(key)) {
+                                        s.copyRules(ruleData);
+                                    }
+                                }
+                            }
+                        }
+                        // if typePK is 'A', make it '*', if it is '*' make it null
+                        typePK=WILDCARD.equals(typePK) == false ? WILDCARD : null;
+                        
+                    } while(typePK != null);
+                    
+                    c -= TYPE_BIT;
+                    continue;
+                }
+                    
+                // SimpleSelector always has a type which defaults to '*'
+                case STYLECLASS_BIT: 
+                    c -= STYLECLASS_BIT;
+                    break;
+                    
+                default:
+                    assert(false);
+            }
+        }
+        
+        Collections.sort(ruleData);
+        
+        // TODO: Unfortunate copy :(
+        List<Rule> rules = new ArrayList<Rule>(ruleData.size());
+        for (int r=0,rMax=ruleData.size(); r<rMax; r++) {
+            final RuleData datum = ruleData.get(r);
+            rules.add(datum.rule);
+        }
+        return rules;
+    }
+
+}
--- a/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Fri Sep 14 10:20:59 2012 -0700
@@ -40,6 +40,105 @@
 final public class SimpleSelector extends Selector {
     static final private Object MAX_CLASS_DEPTH = 255;
     
+    //
+    // The Long value is a bit mask. The upper 4 bits of the mask are used to
+    // hold the index of the mask within the long[] and the remaining bits are
+    // used to hold the mask value. If, for example, "foo" is the 96th entry in
+    // styleClassMask, the upper 4 bits will be 0x01 (foo will be at mask[1]) 
+    // and the remaining bits will have the 36th bit set. 
+    //
+    // When creating the long[] bit set, you get the value from styleClassMask,
+    // mask and shift the upper 4 bits to get the index of the style class in 
+    // the long[], then or the value from styleClassMask with the mask[index]. 
+    // In our example, "foo" will always be at mask[1]
+    //
+    private static final Map<String,Long> styleClassMask = new HashMap<String,Long>();
+    
+    
+    // 4 is arbitrary but allows for 960 style classes. Well, actually 
+    // less since the first bit of each mask[index>0] is wasted since
+    // 61 % 60 is 1, even though the 61st entry is the zeroth value in mask[1]. 
+    // So, 945 style classes.
+    private static final int VALUE_BITS = Long.SIZE-4;
+    
+    // 0x0fffffffffffffff
+    private static final long VALUE_MASK = ~(0xfL << VALUE_BITS);
+        
+    /** 
+     * Convert styleClass string to a bit mask
+     * @param styleClass
+     * @return The upper 4 bits is an index into the long[] mask representation 
+     * of styleClasses. The remaining bits are the bit mask for this styleClass
+     * within the mask[index]
+     */
+    public static long getStyleClassMask(String styleClass) {
+        Long mask = styleClassMask.get(styleClass);
+        if (mask == null) {
+            final int size = styleClassMask.size();
+            final long element = size / VALUE_BITS; // use top bits for element
+            final int exp = size % VALUE_BITS; // remaining bits for value
+            mask = Long.valueOf(
+                (element << VALUE_BITS) | (1L << exp) // same as Math.pow(2,exp)
+            ); 
+            styleClassMask.put(styleClass, mask);
+        }
+        return mask.longValue();
+    }
+
+    /**
+     * Convert a list of style class strings to an array of bit masks.
+     * @param styleClasses
+     * @return The upper 4 bits of each element is an index into the long[] mask
+     * representation of styleClasses. The remaining bits of each element are 
+     * the bit mask for this styleClass within the mask[index]
+     */
+    public static long[] getStyleClassMasks(List<String> styleClasses) {
+        
+        long[] mask = new long[0]; // return zero length if styleClasses is null
+        
+        final int max = styleClasses != null ? styleClasses.size() : -1;
+        for (int n=0; n<max; n++) {
+            final String styleClass = styleClasses.get(n);
+            final long m = getStyleClassMask(styleClass);
+            final long element = (m & ~VALUE_MASK);
+            final int  index = (int)(element >> VALUE_BITS);
+            // need to grow?
+            if (index >= mask.length) {
+                final long[] temp = new long[index+1];
+                System.arraycopy(mask, 0, temp, 0, mask.length);
+                mask = temp;
+            }
+            mask[index] = mask[index] | m;
+        }
+        return mask;
+    }
+
+    public static List<String> getStyleClassStrings(long[] mask) {
+        
+        if (mask == null || mask.length == 0) return Collections.EMPTY_LIST;
+
+        final Map<Long,String> stringMap = new HashMap<Long,String>();
+        for (Map.Entry<String,Long> entry : styleClassMask.entrySet()) {
+            stringMap.put(entry.getValue(), entry.getKey());
+        }
+        final List<String> strings = new ArrayList<String>();
+        for(int index=0; index<mask.length; index++) {
+            final long m = mask[index];
+            final long element = (m & ~VALUE_MASK);
+            for (int exp=0; exp < VALUE_BITS; exp++) {
+                final long key = element | ((1L << exp) & m);
+                if (key != 0) {
+                    final String value = stringMap.get(key);
+                    if (value != null) strings.add(value);
+                }
+            }
+        }
+        // even though the list returned could be modified without causing 
+        // harm, returning an unmodifiableList is consistent with 
+        // SimpleSelector.getStyleClasses()         
+        return Collections.unmodifiableList(strings);
+    }    
+    
     /**
      * If specified in the CSS file, the name of the java class to which
      * this selector is applied. For example, if the CSS file had:
@@ -56,15 +155,20 @@
         return name;
     }
     
-    final private List<String> styleClasses;
-    
     /**
      * @return Immutable List&lt;String&gt; of style-classes of the selector
      */
     public List<String> getStyleClasses() {
-        return styleClasses;
+        return getStyleClassStrings(styleClassMasks);
     }
 
+    long[] getStyleClassMasks() {
+        return styleClassMasks;
+    }
+    
+    /** styleClasses converted to a set of bit masks */
+    final private long[] styleClassMasks;
+    
     final private List<String> pseudoclasses;
     /**
      * @return Immutable List&lt;String&gt; of pseudo-classes of the selector
@@ -103,11 +207,11 @@
         // then match needs to check name
         this.matchOnName = (name != null && !("".equals(name)) && !("*".equals(name)));
 
-        this.styleClasses = 
-                (styleClasses != null) 
-                ? Collections.unmodifiableList(styleClasses)  
-                : Collections.EMPTY_LIST;
-        this.matchOnStyleClass = (this.styleClasses.size() > 0);
+        this.styleClassMasks = 
+                (styleClasses != null && styleClasses.isEmpty() == false)
+                ? getStyleClassMasks(styleClasses)
+                : new long[0];
+        this.matchOnStyleClass = (this.styleClassMasks.length > 0);
 
         this.pseudoclasses = 
                 (pseudoclasses != null) 
@@ -120,6 +224,38 @@
         this.matchOnId = (id != null && !("".equals(id)));
 
     }
+    
+    /** copy constructor used by StyleManager */
+    SimpleSelector(final SimpleSelector other) {
+        
+        this.name = other.name;
+        this.matchOnName = other.matchOnName;
+        
+        if (other.matchOnStyleClass) {
+            final int length = other.styleClassMasks.length;
+            final long[] src = other.styleClassMasks;
+            final long[] dest = this.styleClassMasks = new long[length];
+            System.arraycopy(src, 0, dest, 0, length);
+        } else {
+            // other is long[0]
+            this.styleClassMasks = other.styleClassMasks;
+        }
+        this.matchOnStyleClass = other.matchOnStyleClass;
+        
+        if (other.pseudoclasses != null && other.pseudoclasses.isEmpty() == false) {
+            final List<String> temp = new ArrayList<String>(other.pseudoclasses.size());
+            for(int p=0, pMax=other.pseudoclasses.size(); p<pMax; p++) {
+                temp.add(other.pseudoclasses.get(p));
+            }
+            this.pseudoclasses = Collections.unmodifiableList(temp);
+        } else {
+            this.pseudoclasses = Collections.EMPTY_LIST;
+        }
+        this.pclassMask = other.pclassMask;
+        
+        this.id = other.id;
+        this.matchOnId = other.matchOnId;
+    }
 
     /**
      * Returns a {@link Match} if this selector matches the specified object, or 
@@ -133,7 +269,11 @@
     Match matches(final Node node) {
         if (applies(node)) {
             final int idCount = (matchOnId) ? 1 : 0;
-            return new Match(this, pseudoclasses, idCount, styleClasses.size());
+            int styleClassCount = 0;
+            for (int n=0; n<styleClassMasks.length; n++) {
+                styleClassCount += Long.bitCount(styleClassMasks[n] & VALUE_MASK);
+            }
+            return new Match(this, pseudoclasses, idCount, styleClassCount);
         }
         return null;
     }
@@ -157,12 +297,16 @@
     }
 
     @Override 
-    public boolean applies(final Node node) {
+    public boolean applies(Node node) {
+        
+        final StyleHelper styleHelper = node.impl_getStyleHelper();
+        final SimpleSelector selector = styleHelper.getSimpleSelector();
+        
         // if the selector has an id,
         // then bail if it doesn't match the node's id
         // (do this first since it is potentially the cheapest check)
         if (matchOnId) {
-            boolean idMatch = id.equals(node.getId());
+            boolean idMatch = id.equals(selector.id);
             if (!idMatch) return false;
         }
 
@@ -170,27 +314,18 @@
         // then bail if it doesn't match the node's class name
         // if not wildcard, then match name with node's class name
         if (matchOnName) {
-            final String className = node.getClass().getName();
-            boolean classMatch = nameMatchesAtEnd(className);
+            boolean classMatch = nameMatchesAtEnd(selector.name);
             if (!classMatch) return false;
         }
 
         if (matchOnStyleClass) {
-            boolean styleClassMatch = matchStyleClasses(node.getStyleClass());
+            boolean styleClassMatch = matchStyleClasses(selector.styleClassMasks);                
             if (!styleClassMatch) return false;
         }
         return true;
     }
 
     @Override
-    boolean mightApply(final String className, final String id, final List<String> styleClasses) {
-        if (matchOnName && nameMatchesAtEnd(className)) return true;
-        if (matchOnId   && this.id.equals(id)) return true;
-        if (matchOnStyleClass) return matchStyleClasses(styleClasses);
-        return false;
-    }
-
-    @Override
     boolean stateMatches(final Node node, long states) {
         return ((pclassMask & states) == pclassMask);
     }
@@ -227,8 +362,8 @@
     //
     // This rule matches when class="pastoral blue aqua marine" but does not
     // match for class="pastoral blue".
-    private boolean matchStyleClasses(final List<String> nodeStyleClasses) {
-        return isSubsetOf(styleClasses, nodeStyleClasses);
+    private boolean matchStyleClasses(long[] nodeStyleClasses) {
+        return isSubsetOf(styleClassMasks, nodeStyleClasses);
     }
 
     /**
@@ -241,36 +376,20 @@
       * return true if seq1 is a subset of seq2. That is, all the strings
       * in seq1 are contained in seq2
       */
-    boolean isSubsetOf(final List<String> seq1, final List<String> seq2) {
+    boolean isSubsetOf(long[] seq1, long[] seq2) {
+        
         // if one or the other is null, then they are a subset if both are null
         if (seq1 == null || seq2 == null) return seq1 == null && seq2 == null;
         
         // they are a subset if both are empty
-        if (seq1.isEmpty() && seq2.isEmpty()) return true;
+        if (seq1.length == 0 && seq2.length == 0) return true;
 
         // [foo bar] cannot be a subset of [foo]
-        if (seq1.size() > seq2.size()) return false;
-
-        // is [foo] a subset of [foo bar bang]?
-        // Just need to find the first string in seq2 that equals seq1[0]
-        if (seq1.size() == 1) {
-            final String otherString = seq1.get(0);
-            if (otherString == null) return false;
-
-            for (int n=0, max=seq2.size(); n<max; n++) {
-                String item = seq2.get(n);
-                if (item == null) continue;
-                if (item.equals(otherString)) return true;
-            }
-            return false;
-        }
+        if (seq1.length > seq2.length) return false;
 
         // is [foo bar] a subset of [foo bar bang]?
-        // Check if each string in seq1 is in seq2
-        strSet.clear();
-        for (int n=0, max=seq2.size(); n<max; n++) strSet.add(seq2.get(n));
-        for (int n=0, max=seq1.size(); n<max; n++) {
-            if (! strSet.contains(seq1.get(n))) return false;
+        for (int n=0, max=seq1.length; n<max; n++) {
+            if ((seq1[n] & seq2[n]) != seq1[n]) return false;
         }
         return true;
 
@@ -294,7 +413,9 @@
         if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
             return false;
         }
-        if (this.styleClasses != other.styleClasses && (this.styleClasses == null || !this.styleClasses.equals(other.styleClasses))) {
+        if (this.styleClassMasks != other.styleClassMasks && 
+                (this.styleClassMasks == null || 
+                    !Arrays.equals(this.styleClassMasks, other.styleClassMasks))) {
             return false;
         }
         return true;
@@ -306,7 +427,7 @@
     @Override public int hashCode() {
         if (hash == -1) {
             hash = name.hashCode();
-            hash = 31 * (hash + styleClasses.hashCode());
+            hash = 31 * (hash + (styleClassMasks != null ? Arrays.hashCode(styleClassMasks) : 37));
             hash = 31 * (hash + (id != null ? id.hashCode() : 1229));
             hash = 31 * (int)(pclassMask ^ (pclassMask >>> 32));
         }
@@ -318,9 +439,12 @@
         StringBuilder sbuf = new StringBuilder();
         if (name != null && name.isEmpty() == false) sbuf.append(name);
         else sbuf.append("*");
-        for (int n=0; n<styleClasses.size(); n++) {
-            sbuf.append('.');
-            sbuf.append(styleClasses.get(n));
+        if (styleClassMasks != null && styleClassMasks.length > 0) {
+            List<String> strings = getStyleClassStrings(styleClassMasks);
+            for(String styleClass : strings) {
+                sbuf.append('.');
+                sbuf.append(styleClass);
+            }
         }
         if (id != null && id.isEmpty() == false) {
             sbuf.append('#');
@@ -338,6 +462,7 @@
     {
         super.writeBinary(os, stringStore);
         os.writeShort(stringStore.addString(name));
+        final List<String> styleClasses = getStyleClasses();
         os.writeShort(styleClasses.size());
         for (String sc  : styleClasses) os.writeShort(stringStore.addString(sc));
         os.writeShort(stringStore.addString(id));
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Fri Sep 14 10:20:59 2012 -0700
@@ -35,7 +35,6 @@
 import java.util.Map.Entry;
 import javafx.beans.value.WritableValue;
 import javafx.scene.Node;
-import javafx.scene.Parent;
 import javafx.scene.Scene;
 import javafx.scene.text.Font;
 import javafx.scene.text.FontPosture;
@@ -46,6 +45,7 @@
 import com.sun.javafx.css.converters.FontConverter;
 import com.sun.javafx.css.parser.CSSParser;
 import com.sun.javafx.logging.PlatformLogger;
+import java.util.Collection;
 
 /**
  * The StyleHelper is a helper class used for applying CSS information to Nodes.
@@ -53,7 +53,7 @@
  * same id/styleClass combination (ie: if the same exact set of styles apply
  * to the same nodes, then they should be able to use the same StyleHelper).
  */
-public class StyleHelper {
+final public class StyleHelper {
 
     private static final PlatformLogger LOGGER = com.sun.javafx.Logging.getCSSLogger();
 
@@ -69,37 +69,54 @@
     private static final CalculatedValue SKIP = new CalculatedValue(new int[0], null, false);
 
     /**
-     * Constructs and returns a StyleHelper for the given sequence of styles.
-     * This function is mandatory for creation of a StyleHelper because we want
-     * to reduce the memory usage of the helper and so don't want to specify the
-     * styles directly on the helper, but also need to process the styles into a
-     * lookup table and want that code to be localized to the StyleHelper
-     * script file.
-     * <p>
-     * The pseudoclassStateMask contains the set of pseudoclass states
-     * which, if they change on the nodes that use this StyleHelper, will cause
-     * that the node and all children be updated on the next CSS pass. For
-     * example, if you have a Button, then when the "hover" changes on the
-     * button you want the Button to be marked as needing an UPDATE. However, if
-     * the "hover" state changes on the root of the scene graph you don't want
-     * to update any CSS styles at all (unless of course you had a rule that
-     * indicated that a change in the hover state of the root node should affect
-     * everything). This is computed in the StyleManager and passed here.
-     * @param styles List of the styles. Use an ArrayList for good performance.
+     * Creates a new StyleHelper.
      */
-    public static StyleHelper create(
-            Node node,
-            Map<String, List<CascadingStyle>> smap, 
-            Map<StyleCacheKey, StyleCacheBucket> containerStyleCache,  
-            long pseudoclassStateMask, 
-            long uniqueId) {
+    public StyleHelper(Node node) {
+        this.node = node;
+    }
+    
+    /**
+     * Called from StyleManager when a Node needs to reapply styles, 
+     * this method causes the StyleHelper to adopt the style map and 
+     * reinitialize its internals.
+     */
+    public void setStyles(StyleManager styleManager) {
 
-        // since node doesn't have a stylehelper yet and getKeys
-        // needs the stylehelper uniqueId, we get the keys for 
-        // the parent chain, but will start counting at 1 to 
-        // accomodate for this stylehelper that we are creating.
-        final long[] keys = getKeys(node.getParent(), 1);
-        keys[0] = uniqueId;
+        // We could be here because the node changed id or styleclass, 
+        // so the selector needs to be recreated. Setting it to null
+        // causes the next call to getSimpleSelector() to create it anew.
+        this.simpleSelector = null;
+        
+        StyleManager.StyleMap styleMap = 
+                styleManager.findMatchingStyles(node, this.getSimpleSelector());            
+
+        final Map<String, List<CascadingStyle>> smap = styleMap != null ? styleMap.map : null;
+        if (smap == null || smap.isEmpty()) {
+            
+            // If there are no styles at all, then return
+            final String inlineStyles = node.getStyle();
+            if (inlineStyles == null || inlineStyles.trim().isEmpty()) {
+                
+                this.key = 0;
+                this.smapRef = null;
+                this.sharedStyleCacheRef = null;
+                this.localStyleCache = null;
+                this.pseudoclassStateMask = 0;
+                this.fontProp = null;
+
+                return;
+            }
+        }
+        
+        this.smapRef = new WeakReference<Map<String, List<CascadingStyle>>>(smap);
+        
+        // need to know how far we are to root in order to init arrays.
+        Node parent = node;
+        int depth = 0;
+        while(parent != null) {
+            depth++;
+            parent = parent.getParent();
+        }
         
         // The List<CacheEntry> should only contain entries for those
         // pseudoclass states that have styles. The StyleHelper's
@@ -110,57 +127,60 @@
         // are gotten. By comparing the actual pseudoclass state to the
         // pseudoclass states that apply, a CacheEntry can be created or
         // fetched using only those pseudoclasses that matter.
-        final long[] pclassMasks = new long[keys.length];
-        pclassMasks[0] = pseudoclassStateMask;
-        int n = 1;
-        Node parent = node.getParent();
-        while (parent != null) {
-            final StyleHelper parentHelper = parent.impl_getStyleHelper();
-            pclassMasks[n++] =
-                (parentHelper != null) ? parentHelper.pseudoclassStateMask : 0;
-            parent = parent.getParent();
+        final long[] pclassMasks = new long[depth];
+        
+        final Collection<List<CascadingStyle>> smapValues = smap.values();
+        final List<CascadingStyle>[] styles = smapValues.toArray(new List[smapValues.size()]);
+        for (int i=0; i<styles.length; i++) {
+            for (int j=0, jMax=styles[i].size(); j<jMax; j++) {
+                final CascadingStyle style = styles[i].get(j);
+                final Selector selector = style.getSelector();
+                setPseudoclassStateMasks(node, selector, pclassMasks);
+            }
         }
         
         // TODO: move initialization of localStyleCache somewhere else.
         //       It should not be hidden down here. Maybe to getCacheEntry
-        final StyleCacheBucket localStyleCache = new StyleCacheBucket(pclassMasks);
+        this.localStyleCache = new StyleCacheBucket(pclassMasks);
+
+        long[] keys = new long[depth];
+        this.key = keys[0] = styleMap.uniqueId;
+        parent = node.getParent();
+        for(int k=1; k<depth; k++) {
+            final StyleHelper helper = parent.impl_getStyleHelper();            
+            keys[k] = helper.key;
+            parent = parent.getParent();
+        }
         
-        final StyleCacheKey styleCacheKey = new StyleCacheKey(keys);        
+        final StyleCacheKey styleCacheKey = new StyleCacheKey(keys); 
         //
         // Look to see if there is already a cache for this set of helpers
         //
-        StyleCacheBucket sharedStyleCache = containerStyleCache.get(styleCacheKey);
+        Map<StyleCacheKey, StyleCacheBucket> styleCache = styleManager.getStyleCache();
+        StyleCacheBucket sharedStyleCache = styleCache.get(styleCacheKey);
         if (sharedStyleCache == null) {
             sharedStyleCache = new StyleCacheBucket(pclassMasks);
-            containerStyleCache.put(styleCacheKey, sharedStyleCache);
+            styleCache.put(styleCacheKey, sharedStyleCache);
         }
+        this.sharedStyleCacheRef = new WeakReference<StyleCacheBucket>(sharedStyleCache);
              
-        WritableValue fontProp = null;
+        this.fontProp = null;
         final List<StyleableProperty> props = node.impl_getStyleableProperties();
         final int pMax = props != null ? props.size() : 0;
         for (int p=0; p<pMax; p++) {
             final StyleableProperty prop = props.get(p);
             if ("-fx-font".equals(prop.getProperty())) {                
-                fontProp = prop.getWritableValue(node);
+                this.fontProp = prop.getWritableValue(node);
                 break;
             }
+        }        
+        
+        if (LOGGER.isLoggable(PlatformLogger.FINE)) {
+            LOGGER.fine(node + " " + key);
         }
-        final StyleHelper helper = 
-            new StyleHelper(
-                smap, 
-                fontProp,
-                localStyleCache,
-                sharedStyleCache,
-                pseudoclassStateMask, 
-                uniqueId);
-
-        if (LOGGER.isLoggable(PlatformLogger.FINE)) {
-            LOGGER.fine(node + " " + uniqueId);
-        }
-        return helper;
     }
 
-    private final long key;
+    private long key;
 
     /*
      * A cache to store values from lookup.
@@ -213,7 +233,7 @@
      * 
      * Note that the Map is created as a WeakHashMap in StyleManager. 
      */
-    private final Reference<StyleCacheBucket> sharedStyleCacheRef;
+    private Reference<StyleCacheBucket> sharedStyleCacheRef;
     
     private StyleCacheBucket getSharedStyleCache() {
         final StyleCacheBucket styleCache = sharedStyleCacheRef.get();
@@ -223,9 +243,9 @@
     /**
      * A place to store calculated values that cannot be stored in shared cache
      */
-    private final StyleCacheBucket localStyleCache;
+    private StyleCacheBucket localStyleCache;
     
-    public static class StyleCacheKey {
+    final static class StyleCacheKey {
         private final long[] keys;
         
         private StyleCacheKey(long[] keys) {
@@ -257,16 +277,48 @@
     }
     
     //
-    // The key is created from the index of this StyleHelper
-    // and the hash of all the Node's parents.
-    // The key is unique to the path to the Node that owns this .
-    //    
-    private static long[] getKeys(Node node, int count) {
-        if (node == null) return new long[count];
-        long[] keys = getKeys(node.getParent(), ++count);
-        final StyleHelper sh = node.impl_getStyleHelper();        
-        keys[count-1] = sh != null ? sh.key : 0;
-        return keys;
+    // get pseudoclass state from the selector and set it in the mask.
+    //
+    private static void setPseudoclassStateMasks(Node node, Selector selector, long[] masks) {
+        
+        if (selector instanceof CompoundSelector) {
+            final CompoundSelector compoundSelector = (CompoundSelector)selector;
+            final List<SimpleSelector> selectors = compoundSelector.getSelectors();
+            
+            Node parent = node;
+            int  index = 0;
+            // Loop control variable decreases but index increases because
+            // selectors run right to left, but mask runs child to root.
+            // 
+            for (int n=selectors.size()-1; 0<=n; --n) {
+                
+                final SimpleSelector simpleSelector = selectors.get(n);
+                
+                while(parent != null && simpleSelector.applies(parent) == false) {
+                    parent = parent.getParent();
+                    index += 1;
+                }
+                
+                assert(parent != null);
+                long bits = StyleManager.getPseudoclassMask(simpleSelector.getPseudoclasses());
+                masks[index] |= bits;
+                
+                // update the corresponding StyleHelper's pseudoclassStateMask
+                // since this is state that affects children.
+                StyleHelper styleHelper = parent.impl_getStyleHelper();
+                styleHelper.pseudoclassStateMask |= bits;
+                
+            }
+        } else {
+            SimpleSelector simpleSelector = (SimpleSelector)selector;
+            long bits = StyleManager.getPseudoclassMask(simpleSelector.getPseudoclasses());
+            masks[0] |= bits;
+
+            // update the StyleHelper's pseudoclassStateMask
+            // since this is state that matters.
+            StyleHelper styleHelper = node.impl_getStyleHelper();
+            styleHelper.pseudoclassStateMask |= bits;
+        }
     }
         
     /**
@@ -290,7 +342,7 @@
     /**
      * A drop in the StyleCacheBucket.
      */
-    static class CacheEntry {
+    final static class CacheEntry {
 
         private final long[] states;
         private final Map<String,CalculatedValue> values;
@@ -363,7 +415,8 @@
         //
         // Find the entry in local cache that matches the states
         //
-       
+        if (localStyleCache == null) return null;
+        
         //
         // pclassMask is the set of pseudoclasses that appear in the
         // style maps of this set of StyleHelpers. Calculated values are
@@ -437,7 +490,7 @@
         return localCacheEntry;
     }
 
-    public void clearLocalCache() {
+    private void clearLocalCache() {
         final List<CacheEntry> entries = localStyleCache.entries;
         final int max = entries.size();
         for (int n=0; n<max; n++) {
@@ -452,10 +505,10 @@
      * the lookup time for each property. The smap is shared and is owned
      * by the StyleManager Cache.
      */
-    private final Reference<Map<String, List<CascadingStyle>>> smapRef;
+    private Reference<Map<String, List<CascadingStyle>>> smapRef;
 
     private Map<String, List<CascadingStyle>> getStyleMap() {
-        final Map<String, List<CascadingStyle>> smap = smapRef.get();
+        final Map<String, List<CascadingStyle>> smap = smapRef != null ? smapRef.get() : null;
         return smap;
     }
     
@@ -479,32 +532,39 @@
      * button and all children to be update. Other pseudoclass state changes
      * that are not in this hash set are ignored.
      */
-    private final long pseudoclassStateMask;
+    private long pseudoclassStateMask;
 
-    private final WritableValue fontProp;
-    /**
-     * Creates a new StyleHelper.
-     *
-     * @param pseudoclassStateMask A set of bits for each pseudoclass
-     *        who's change may impact children of this node. This is used as
-     *        an important performance optimization so that pseudoclass state
-     *        changes which do not affect any children do not get handled.
+    /** The node's font property, if there is one */
+    private WritableValue fontProp;
+
+    /** 
+     * The node to which this selector belongs. StyleHelper is a final in Node.
      */
-    private StyleHelper(
-            Map<String, List<CascadingStyle>> smap, 
-            WritableValue fontProp,
-            StyleCacheBucket localStyleCache,
-            StyleCacheBucket sharedStyleCache,
-            long pseudoclassStateMask, 
-            long key) {
-        this.key = key;
-        this.smapRef = new WeakReference<Map<String, List<CascadingStyle>>>(smap);
-        this.sharedStyleCacheRef = new WeakReference<StyleCacheBucket>(sharedStyleCache);
-        this.localStyleCache = localStyleCache;
-        this.pseudoclassStateMask = pseudoclassStateMask;
-        this.fontProp = fontProp;
+    private final Node node;
+    
+    /** 
+     * The Node's name, id and style-class as a Selector. This is used as a 
+     * key to the StyleManager's Cache.
+     */
+    private SimpleSelector simpleSelector;
+            
+    SimpleSelector getSimpleSelector() {
+
+        if (simpleSelector == null) {
+
+            final String name = node.getClass().getName();
+            final String id = node.getId();
+            final List<String> selectorStyleClasses = node.getStyleClass();
+            simpleSelector = new SimpleSelector(
+                    name,
+                    selectorStyleClasses,
+                    null,
+                    id);
+        }            
+        
+        return simpleSelector;
     }
-
+    
     /**
      * Invoked by Node to determine whether a change to a specific pseudoclass
      * state should result in the Node being marked dirty with an UPDATE flag.
@@ -555,7 +615,7 @@
      * in the stylesheet. There is no need to do selector matching here since
      * the stylesheet is from parsing Node.style.
      */
-    private Map<String,CascadingStyle> getStyles(Stylesheet authorStylesheet) {
+    private static Map<String,CascadingStyle> getStyles(Stylesheet authorStylesheet) {
 
         final Map<String,CascadingStyle> authorStyles = new HashMap<String,CascadingStyle>();
         if (authorStylesheet != null) {
@@ -589,7 +649,7 @@
     /**
      * Get the mapping of property to style from Node.style for this node.
      */
-    private Map<String,CascadingStyle> getInlineStyleMap(Node node) {
+    private static Map<String,CascadingStyle> getInlineStyleMap(Node node) {
 
         return getInlineStyleMap(node.impl_getStyleable());
     }
@@ -597,7 +657,7 @@
     /**
      * Get the mapping of property to style from Node.style for this node.
      */
-    private Map<String,CascadingStyle> getInlineStyleMap(Styleable styleable) {
+    private static Map<String,CascadingStyle> getInlineStyleMap(Styleable styleable) {
         
         final String inlineStyles = styleable.getStyle();
 
@@ -641,51 +701,26 @@
     }
     
     /* 
-     * Called from transitionToState to set the pseudoClassStates member. This method
-     * gets the pseudoClassStates from the first non-null StyleHelper of a Parent and
-     * fills in the gaps with zeros (no state) for those parents that have no StyleHelper.
-     * This works because styles are applied from the top-down. So the StyleHelper of
-     * the parent will already have pseudoClassStates set to the correct value.
-     * 
      * Note Well: The array runs from leaf to root. That is 
      * pseudoClassStates[0] is the states for node and 
      * pseudoClassStates[1..(pseudoClassStates.length-1)] is the states for the 
-     * node's parents. This is how the code was written when the pseudoClassState
-     * was looked up recursively, so we'll leave it that way for now.
+     * node's parents.
      */ 
-    private static void setPseudoClassStatesForTransition(Node node, StyleHelper styleHelper) {
+    private static long[] getPseudoClassStatesForTransition(Node node, int count) {
     
+        if (node == null) return new long[count];
         
-        long[] parentStates = null;
-        // count up parents that don't have a stylehelper until we get to 
-        // the first parent with a stylehelper. The state for the missing
-        // stylehelpers will be zero. 
-        int nMissing = 0; 
+        long[] states = getPseudoClassStatesForTransition(node.getParent(), ++count);
         
-        Parent parent = node.getParent();
-        while (parent != null && parentStates == null) {
-            final StyleHelper helper = parent.impl_getStyleHelper();
-            if (helper != null) {
-                parentStates = helper.pseudoClassStates; 
-            } else {
-                parent = parent.getParent();
-                nMissing += 1;
-            }
-        }
+        StyleHelper helper = node.impl_getStyleHelper();
         
-        final long nodeState = node.impl_getPseudoClassState();
-        final int nParents = parentStates != null ? parentStates.length + nMissing : nMissing;
-        // do we need to init pseudoClassStates or can we reuse?
-        if (styleHelper.pseudoClassStates == null || styleHelper.pseudoClassStates.length < nParents) {
-            styleHelper.pseudoClassStates = new long[nParents + 1];            
-        }
-        Arrays.fill(styleHelper.pseudoClassStates, 0);
-        styleHelper.pseudoClassStates[0] = nodeState;
-        
-        if (parentStates != null) {
-            System.arraycopy(parentStates, 0, styleHelper.pseudoClassStates, nMissing+1, parentStates.length);
-        }
-        
+        // avoid calling impl_getPseudoClassState if there 
+        // aren't any pseudoclasses that matter
+        states[count-1] = (helper.pseudoclassStateMask != 0) 
+                ? node.impl_getPseudoClassState() & helper.pseudoclassStateMask
+                : 0;
+
+        return states;
     }
     
     /* 
@@ -695,7 +730,7 @@
      * isShared is true if the value is not specific to a node. 
      * 
      */
-    private static class CalculatedValue {
+    final private static class CalculatedValue {
         final Object value;
         final Origin origin;
         final boolean isRelative;
@@ -719,16 +754,16 @@
      * is disabled until the new parser comes online with support for
      * animations and that support is detectable via the API.
      */
-    public void transitionToState(Node node) {
+    public void transitionToState() {
 
-        if (smapRef.get() == null) return;
-        
+        if (smapRef == null || smapRef.get() == null) return;
+
         //
         // The ValueCacheEntry to choose depends on this Node's state and
         // the state of its parents. Without the parent state, the fact that
         // this node in this state matched foo:blah bar { } is lost.
         //
-        setPseudoClassStatesForTransition(node, this);
+        pseudoClassStates = getPseudoClassStatesForTransition(node, 0);
 
         // allstates[0] is this node's state
         long states = pseudoClassStates[0];
@@ -928,24 +963,6 @@
     }
 
     /**
-     * Called by the Scene whenever it has transitioned from one set of
-     * pseudoclass states to another. This function will then lookup the
-     * new values for each of the styleable variables on the Scene, and
-     * then either set the value directly or start an animation based on
-     * how things are specified in the CSS file. Currently animation support
-     * is disabled until the new parser comes online with support for
-     * animations and that support is detectable via the API.
-     */
-    public void transitionToState(Scene scene, List<String> states) {
-        // TODO the majority of this function is exactly the same as the
-        // Node variant. We also need to implement the lookup for the
-        // scene, but don't have to worry about inherit. If only Scene were
-        // an actual Parent node... might be a good idea except that its
-        // scene variable then makes no sense. I guess it would be null??
-        throw new UnsupportedOperationException("not yet implemented");
-    }
-
-    /**
      * Gets the CSS CascadingStyle for the property of this node in these pseudoclass
      * states. A null style may be returned if there is no style information
      * for this combination of input parameters.
@@ -1240,7 +1257,7 @@
      */
     private CascadingStyle resolveRef(Node node, String property, long states,
             Map<String,CascadingStyle> userStyles) {
-
+        
         final CascadingStyle style = getStyle(node, property, states, userStyles);
         if (style != null) {
             return style;
@@ -1441,7 +1458,7 @@
 
         final ParsedValue cssValue = style.getParsedValue();
         if (cssValue != null && !("null").equals(cssValue.getValue())) {
-        
+
             final ParsedValue resolved = 
                 resolveLookups(node, cssValue, states, inlineStyles, styleList);
             
@@ -1613,19 +1630,18 @@
 
         if (child == null) return null;
         
+        CacheEntry parentCacheEntry = null;
         Node parent = child;
         StyleHelper parentHelper = null;
         do {
             parent = parent.getParent();
-        } while (parent != null &&
-                    (parentHelper = parent.impl_getStyleHelper()) == null);
+            if (parent != null) {
+                parentHelper = parent.impl_getStyleHelper();
+                final long[] pstates = parentHelper.getPseudoClassStates();
+                parentCacheEntry = parentHelper.getCacheEntry(parent, pstates);                
+            }
+        } while (parent != null && parentCacheEntry == null);
 
-        CacheEntry parentCacheEntry = null;
-        if (parent != null && parentHelper != null) {
-            final long[] pstates = parentHelper.getPseudoClassStates();
-            parentCacheEntry = parentHelper.getCacheEntry(parent, pstates);
-//            assert(parentCacheEntry.font != null);
-        }
         return parentCacheEntry;
     }
    
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Fri Sep 14 10:20:59 2012 -0700
@@ -142,7 +142,7 @@
 
         this.owner = owner;
 
-        cacheMap = new HashMap<Key, Cache>();
+        cacheMap = new HashMap<SimpleSelector, Cache>();
 
         referencedStylesheets = new ArrayList<Stylesheet>();
         if (defaultUserAgentStylesheet != null) {
@@ -173,8 +173,7 @@
     // for testing
     List<Stylesheet> getReferencedStylesheets() { return referencedStylesheets; }
     
-    
-    /*
+       /*
      * Scene does not have a inline style, but an applet might. This is
      * the applet's stylesheet from a 'style' attribute. 
      */
@@ -186,9 +185,9 @@
      * The map of Caches, key'd by a combination of class name, style class, and
      * id.
      */
-    protected final Map<Key, Cache> cacheMap;
+    protected final Map<SimpleSelector, Cache> cacheMap;
     // for testing
-    Map<Key, Cache> getCacheMap() { return cacheMap; }
+    Map<SimpleSelector, Cache> getCacheMap() { return cacheMap; }
 
     /*
      * The StyleHelper's cached values are relevant only for a given scene.
@@ -197,7 +196,7 @@
      * way, each scene gets its own valueCache.
      */
     private final Map<StyleCacheKey, StyleCacheBucket> styleCache;
-    // for testing
+    /** StyleHelper uses this cache. */
     Map<StyleCacheKey, StyleCacheBucket> getStyleCache() { return styleCache; }
     
     /*
@@ -257,13 +256,13 @@
         final RefList<T> users;
         // the keys for finding Cache entries that use this stylesheet.
         // This list should also be fairly small
-        final RefList<Key> keys;
+        final RefList<SimpleSelector> keys;
 
         StylesheetContainer(String fname, Stylesheet stylesheet) {
             this.fname = fname;
             this.stylesheet = stylesheet;
             this.users = new RefList<T>();
-            this.keys = new RefList<Key>();
+            this.keys = new RefList<SimpleSelector>();
         }
     }
 
@@ -295,7 +294,45 @@
 
     }
 
-    public abstract void updateStylesheets();
+    public void updateStylesheets() {
+     
+        selectorPartitioning.reset();
+
+        // The list of referenced stylesheets is about to be recalculated, 
+        // so clear the current list. The style maps are no longer valid, so
+        // annihilate the cache
+        referencedStylesheets.clear();
+        clearCache();
+
+        if (defaultUserAgentStylesheet != null) {
+            referencedStylesheets.add(defaultUserAgentStylesheet);
+        }
+        
+        if (userAgentStylesheetMap.isEmpty() == false) {
+            // TODO: This isn't right. They should be in the same order that
+            // they were first added.
+            referencedStylesheets.addAll(userAgentStylesheetMap.values());
+        }
+
+        updateStylesheetsImpl();
+        
+        for(int n=0, nMax=referencedStylesheets.size(); n<nMax; n++) {
+            
+            final Stylesheet stylesheet = referencedStylesheets.get(n);
+            final List<Rule> rules = stylesheet.getRules();
+            for (int r=0, rMax=rules.size(); r<rMax; r++) {
+                final Rule rule = rules.get(r);
+                final List<Selector> selectors = rule.getSelectors();
+                for (int s=0, sMax=selectors.size(); s<sMax; s++) {
+                    Selector selector = selectors.get(s);
+                    selectorPartitioning.partition(selector, rule);
+                }
+            }
+        }
+        
+    }
+    
+    protected abstract void updateStylesheetsImpl();
     
     public void stylesheetsChanged(ListChangeListener.Change<String> c) {
         // for now, just call updateStylesheets
@@ -380,6 +417,7 @@
                     ** runtime jar
                     */
                     URI styleManagerJarURI = AccessController.doPrivileged(new PrivilegedExceptionAction<URI>() {
+                            @Override
                             public URI run() throws java.net.URISyntaxException, java.security.PrivilegedActionException {
                             return StyleManager.class.getProtectionDomain().getCodeSource().getLocation().toURI();
                         }
@@ -420,6 +458,7 @@
                             JarFile jar = null;
                             try {
                                 jar = AccessController.doPrivileged(new PrivilegedExceptionAction<JarFile>() {
+                                        @Override
                                         public JarFile run() throws FileNotFoundException, IOException {
                                             return new JarFile(styleManagerJarPath);
                                         }
@@ -591,7 +630,7 @@
         if (fname == null ||  fname.trim().isEmpty()) return;
 
         if (userAgentStylesheetMap.containsKey(fname) == false) {
-
+            
             // RT-20643
             CssError.setCurrentScene(scene);
 
@@ -720,7 +759,10 @@
                 if (value != null) strings.add(value);
             }
         }
-        return strings;
+        // even though the list returned could be modified without causing 
+        // harm, returning an unmodifiableList is consistent with 
+        // SimpleSelector.getStyleClasses()
+        return Collections.unmodifiableList(strings);
     }
 
     protected final void clearCache() {
@@ -733,177 +775,52 @@
         return ++smapCount;
     }
 
-    abstract protected Key getKey(Node node);
-
     /**
-     * Returns a StyleHelper for the given Node, or null if there are no styles
-     * for this node.
+     * Finds matching styles for this Node.
      */
-    public final StyleHelper getStyleHelper(Node node) {
-
-        final Key key = getKey(node);
+    StyleMap findMatchingStyles(Node node, SimpleSelector key) {
+        
+        //
+        // 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 (referencedStylesheets.isEmpty()) {
+            return StyleMap.EMPTY_MAP;
+        }
+        
         Cache cache = cacheMap.get(key);
 
         // If the cache is null, then we need to create a new Cache and
         // add it to the cache map
         if (cache == null) {
+            
+            final String id = key.getId();
+            final String name = key.getName();
+            final long[] styleClassBits = key.getStyleClassMasks();
+            
             // Construct the list of Rules that could possibly apply
-            final List<Rule> rules = new ArrayList<Rule>();
-
-            /*
-             * A Set of all the pseudoclass states which, if they change, need
-             * to cause the Node to be set to UPDATE its CSS styles on the next
-             * pulse. For a full explanation, see the StyleHelper's
-             * mayImpactChildren variable.
-             */
-            long pseudoclassStateMask = 0;
-
-            // If the node can have children, look at the ancestors
-            // in a compound selector for pseudoclassBits
-            final boolean canHaveChildren = node instanceof Parent;
-
-            // It may be that there are no pseudoclassBits in the ancestor
-            // selectors, but if one of the ancestor selectors might apply,
-            // then the selector impacts its children.
-            boolean impactsChildren = false;
-
-            //
-            final String className = node.getClass().getName();
-            final String id = node.getId();
-            final List<String> styleClass = node.getStyleClass();
+            final List<Rule> rules =
+                selectorPartitioning.match(
+                        key.getId(), 
+                        key.getName(), 
+                        key.getStyleClassMasks()
+                    );
             
-            List<Stylesheet> stylesheetsToProcess = referencedStylesheets;
-
-            for (int i = 0, imax = stylesheetsToProcess.size(); i < imax; i++) {
-                final Stylesheet ss = stylesheetsToProcess.get(i);
-
-                final List<Rule> stylesheetRules = ss != null ? ss.getRules() : null;
-                if (stylesheetRules == null || stylesheetRules.isEmpty()) {
-                    continue;
-                }
-
-                for (int j = 0, jmax = stylesheetRules.size(); j < jmax; j++) {
-                    Rule rule = stylesheetRules.get(j);
-                    boolean mightApply = rule.mightApply(className, id, styleClass);
-                    if (mightApply) {
-                        rules.add(rule);
-                    }
-
-                    //
-                    // The following logic used to be in a separate routine,
-                    // but the need to flag compound selectors with no
-                    // pseudoclass state that might impact the node's
-                    // children encouraged moving it here.
-                    //
-
-                    // The following loop creates the pseudoclassStateMask.
-                    // For a leaf node, the loop will just gather the
-                    // pseudoclass state bits. For a parent node, this loop
-                    // looks at the ancestor selectors to see if the parent
-                    // matches. If so, then the pseudoclass state from that
-                    // parent will affect the styling of its child nodes.
-                    // For example, in the selector A:foo B { }, whenever the
-                    // "foo" pseudoclass of A changes it must notify child
-                    // nodes of the change so that if one of them happens to
-                    // be a B it can update itself accordingly. Since this
-                    // can be quite expensive, we want to make sure we
-                    // support this capability only for nodes that need it.
-                    // This function determines whether this support is
-                    // necessary (setting impactsChildren to true),
-                    // and what pseudoclasses on the parent (A) that matter.
-
-                    // The node has to have rules that apply or be a Parent
-                    // in order for the pseudoclass state to matter.
-                    if (!mightApply && !canHaveChildren) {
-                        continue;
-                    }
-
-                    // For each selector, rule, stylesheet look for whether this Node
-                    // is referenced in the ancestor part of the selector, and whether or
-                    // not it also has pseudoclasses specified
-                    final int smax = rule.selectors != null ? rule.selectors.size() : 0;
-                    for (int s = 0; s < smax; s++) {
-                        final Selector selector = rule.selectors.get(s);
-                        if (selector instanceof CompoundSelector) {
-
-                            final CompoundSelector cs = (CompoundSelector) selector;
-                            final List<SimpleSelector> csSelectors = cs.getSelectors();
-
-                            // if mightApply is true, then the right-most selector
-                            // was matched and we just need the pseudoclass state
-                            // from that selector.
-                            if (mightApply) {
-                                final SimpleSelector simple =
-                                        csSelectors.get(csSelectors.size() - 1);
-                                pseudoclassStateMask = pseudoclassStateMask
-                                        | getPseudoclassMask(simple.getPseudoclasses());
-
-
-                                // Otherwise, the rule did not match but we need to check
-                                // to see if this node matches one of the ancestor selectors.
-                                // This only matters for nodes that can have children. You
-                                // wouldn't find a Rectangle, for example, as an ancestor
-                                // in a compound selector (you might, but the selector
-                                // wouldn't match anything)
-                            } else if (canHaveChildren) {
-                                // only check the ancestor selectors. If we are here,
-                                // then we know mightApply is false, meaning the rule
-                                // does not apply to this node because this node does
-                                // not match the right-most selector.
-                                for (int sctr = 0, max_sctr = csSelectors.size() - 1; sctr < max_sctr; sctr++) {
-                                    final SimpleSelector simple = csSelectors.get(sctr);
-                                    if (simple.mightApply(className, id, styleClass)) {
-                                        pseudoclassStateMask = pseudoclassStateMask
-                                                | getPseudoclassMask(simple.getPseudoclasses());
-                                        impactsChildren = true;
-                                    }
-                                }
-                            }
-                            // Not a compound selector. If the selector might apply,
-                            // then save off the pseudoclass state. StyleHelper
-                            // checks this to see if a pseudoclass matters or not.
-                        } else if (mightApply) {
-                            SimpleSelector simple = (SimpleSelector) selector;
-                            pseudoclassStateMask = pseudoclassStateMask
-                                    | getPseudoclassMask(simple.getPseudoclasses());
-                        }
-                    }
-                }
-            }
-
-            //
-            // regardless of whether or not the cache is shared, a Cache
-            // object is still needed in order to do the lookup.
-            //
-            final Key newKey = key.dup();
-
-            cache = new Cache(rules, pseudoclassStateMask, impactsChildren);
+            // create a new Cache from these rules.
+            cache = new Cache(rules);
+            
+            final SimpleSelector newKey = new SimpleSelector(key);                    
             cacheMap.put(newKey, cache);
 
         }
 
-        // the key is an instance variable and so we need to null the
-        // key.styleClass to prevent holding a hard reference to the
-        // styleClass (and its Node)
-        key.styleClass = null;
+        //
+        // Create a style helper for this node from the styles that match. 
+        //
+        StyleMap smap = cache.getStyleMap(this, node);
         
-        // Return the style helper looked up by the cache. The cache will
-        // create a style helper if necessary (and possible), so we don't
-        // have to worry about that part.
-        StyleMap smap = cache.getStyleMap(this, node);
-        if (smap == null) {
-            return null;
-        }
-
-        StyleHelper helper =
-                StyleHelper.create(
-                node,
-                smap.map,
-                styleCache,
-                cache.pseudoclassStateMask,
-                smap.uniqueId);
-        
-        return helper;
+        return smap;        
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -939,9 +856,12 @@
     
     ////////////////////////////////////////////////////////////////////////////
     //
-    // Inner classes
+    // Classes and routines for mapping styles to a Node
     //
     ////////////////////////////////////////////////////////////////////////////
+
+    private final SelectorPartitioning selectorPartitioning = new SelectorPartitioning();
+    
     
     //
     // Used by StyleHelper. The key uniquely identifies this style map.
@@ -955,6 +875,9 @@
             this.uniqueId = key;
             this.map  = map;
         }
+        
+        private static final StyleMap EMPTY_MAP = 
+            new StyleMap(0, Collections.EMPTY_MAP);
 
     }
 
@@ -966,74 +889,120 @@
         // this must be initialized to the appropriate possible rules when
         // the helper cache is created by the StylesheetContainer
         private final List<Rule> rules;
-        private final long pseudoclassStateMask;
-        private final boolean impactsChildren;
         private final Map<Long, StyleMap> cache;
 
-        Cache(List<Rule> rules, long pseudoclassStateMask, boolean impactsChildren) {
+        Cache(List<Rule> rules) {
             this.rules = rules;
-            this.pseudoclassStateMask = pseudoclassStateMask;
-            this.impactsChildren = impactsChildren;
             this.cache = new HashMap<Long, StyleMap>();
         }
 
         private StyleMap getStyleMap(StyleManager owner, Node node) {
-
-            // If this set of rules (which may be empty) impacts children,
-            // then this node will get a StyleHelper.
-            if (!impactsChildren) {
-
-                // Since this set of rules does not impact children, this node
-                // will only get a StyleHelper if there are styles that might
-                // apply. There are styles that might apply if there are rules
-                // or if the node has an in-line style.
-                final String nodeStyle = node.getStyle();
-                final boolean hasStyle = nodeStyle != null && !nodeStyle.isEmpty();
-
-                if (rules.isEmpty() && pseudoclassStateMask == 0 && hasStyle == false) {
-                    boolean hasInheritAsDefault = false;
-                    // TODO This is questionable as what happens when a node has no style helper and inherits styles
-                    final List<StyleableProperty> styleables = node.impl_getStyleableProperties();
-                    final int max = styleables != null ? styleables.size() : 0;
-                    for (int i = 0; i < max; i++) {
-                        if (styleables.get(i).isInherits()) {
-                            hasInheritAsDefault = true;
-                            break;
-                        }
-                    }
-                    // if we have no rules and no inherited properties we don't need a StyleHelper
-                    if (! hasInheritAsDefault) return null;
-                }
+            
+            if (rules == null || rules.isEmpty()) {                
+                return StyleMap.EMPTY_MAP;
             }
 
+
+            //
+            // Since the list of rules is found by matching only the
+            // rightmost selector, the set of rules may larger than those 
+            // rules that actually match the node. The following loop
+            // whittles the list down to those rules that actually match.
+            //
+            // listOfMatches is dual purpose. First, it keeps track
+            // of what rules match the node. Second, it keeps track
+            // of the indices of the matching rules. These indices
+            // are used to create the bit mask for the cache key. If
+            // the cache misses, then a new entry is created by looping
+            // through listOfMatches and creating CascadingStyles for
+            // entries that are not null. Ok, so that's three.
+            //
+            final List<Match>[] listOfMatches = new List[rules.size()];
+            
+            //
+            // do we have a cache for the set of matching rules?
+            //
             // To lookup from the cache, we construct a key from a Long
-            // where the rules that apply to this particular node are
+            // where the rules that match this particular node are
             // represented by bits on the Long.
+            //
             long key = 0;
             long mask = 1;
-            for (int i = 0, imax = rules.size(); i < imax; i++) {
-                Rule rule = rules.get(i);
-                if (rule.applies(node)) {
+            for (int r = 0, rMax = rules.size(); r < rMax; r++) {
+                
+                final Rule rule = rules.get(r);
+                final List<Match> matches = rule.matches(node);
+                if (matches  != null && matches.isEmpty() == false) {
+                    
+                    listOfMatches[r] = matches;
                     key = key | mask;
+                    
+                } else {
+                    
+                    listOfMatches[r] = null;
+                    
                 }
                 mask = mask << 1;
             }
-
+            
+            // nothing matched!
+            if (key == 0) return null;
+            
             final Long keyObj = Long.valueOf(key);
             if (cache.containsKey(keyObj)) {
                 final StyleMap styleMap = cache.get(keyObj);
                 return styleMap;
             }
+                        
+            final List<CascadingStyle> styles = new ArrayList<CascadingStyle>();
+            int ordinal = 0;
+            
+            for (int m = 0, mMax = listOfMatches.length; m<mMax; m++) {
+                
+                final List<Match> matches = listOfMatches[m];
+                if (matches == null) continue; 
+                
+                // the rule that matched
+                Rule rule = rules.get(m);
+                
+                for (int n=0, nMax = matches.size(); n<nMax; n++) {
+                    
+                    final Match match = matches.get(n);
+                    // TODO: should never get nulls in this list. Fix Rule#matches
+                    if (match == null) continue;
+                
+                    for (int k = 0, kmax = rule.declarations.size(); k < kmax; k++) {
+                        final Declaration decl = rule.declarations.get(k);
 
-            // We need to create a new StyleHelper, add it to the cache,
+                        final CascadingStyle s = new CascadingStyle(
+                            new Style(match.selector, decl),
+                            match.pseudoclasses,
+                            match.specificity,
+                            // ordinal increments at declaration level since
+                            // there may be more than one declaration for the
+                            // same attribute within a rule or within a stylesheet
+                            ordinal++
+                        );
+
+                        styles.add(s);
+                    }
+                }
+            }
+
+                // return sorted styles
+            Collections.sort(styles);
+
+            
+            // We need to create a new style map, add it to the cache,
             // and then return it.
-            final List<CascadingStyle> styles = getStyles(node);
             final Map<String, List<CascadingStyle>> smap =
                 new HashMap<String, List<CascadingStyle>>();
-            final int max = styles != null ? styles.size() : 0;
-            for (int i=0; i<max; i++) {
+            
+            for (int i=0, max=styles.size(); i<max; i++) {
+                
                 final CascadingStyle style = styles.get(i);
                 final String property = style.getProperty();
+                
                 // This is carefully written to use the minimal amount of hashing.
                 List<CascadingStyle> list = smap.get(property);
                 if (list == null) {
@@ -1048,121 +1017,7 @@
             return styleMap;
         }
 
-        /**
-         * Looks up all the styles for this Node. This function takes no advantage
-         * of any caches but simply does a complete fresh lookup. The styles
-         * returned are sorted such that the most specific style is first.
-         */
-        private List<CascadingStyle> getStyles(Node node) {
-            // The priority of stylesheets from the CSS spec is
-            // (1) user agent declarations
-            // (2) user normal declarations
-            // (3) author normal declarations
-            // (4) author important declarations
-            // (5) user important declarations
-            // we have the correct order here for 1,2,3 and the 4 & 5
-            // we handle when sorting the styles
-
-            if (rules == null || rules.isEmpty()) return null;
-
-            List<CascadingStyle> styles = new ArrayList<CascadingStyle>(rules.size());
-                // Order in which the declaration of a Style appears (see below)
-                int ordinal = 0;
-                // For each declaration in the matching rules, create a Style object
-                //final List<Style> styles = new ArrayList<Style>();
-                for (int i = 0, imax = rules.size(); i < imax; i++) {
-                    final Rule rule = rules.get(i);
-                    List<Match> matches = rule.matches(node);
-                    for (int j = 0, jmax = matches.size(); j < jmax; j++) {
-                        final Match match = matches.get(j);
-                        if (match == null) continue;
-                        for (int k = 0, kmax = rule.declarations.size(); k < kmax; k++) {
-                            final Declaration decl = rule.declarations.get(k);
-
-                            final CascadingStyle s = new CascadingStyle(
-                                new Style(match.selector, decl),
-                                match.pseudoclasses,
-                                match.specificity,
-                                // ordinal increments at declaration level since
-                                // there may be more than one declaration for the
-                                // same attribute within a rule or within a stylesheet
-                                ordinal++
-                            );
-
-                        styles.add(s);
-                        }
-                    }
-                }
-
-                // return sorted styles
-            Collections.sort(styles);
-            return styles;
-            }
-
-        }
-
-    /**
-     * The key used in the cacheMap of the StylesheetContainer
-     */
-    static class Key {
-        
-        public Key() {
-        }
-
-        protected Key dup() {
-            
-            Key key = new Key();
-            key.className  = className;
-            key.id = id;
-            final int nElements = styleClass.size();
-            key.styleClass = new ArrayList<String>(nElements);
-            for (int n = 0; n < nElements; n++) {
-                key.styleClass.add(styleClass.get(n));
-            }
-            
-            return key;
-        }
-        
-        // note that the class name here is the *full* class name, such as
-        // javafx.scene.control.Button. We only bother parsing this down to the
-        // last part when doing matching against selectors, and so want to avoid
-        // having to do a bunch of preliminary parsing in places where it isn't
-        // necessary.
-        protected String className;
-        protected String id;
-        protected List<String> styleClass;
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o instanceof Key) {
-                Key other = (Key)o;
-                boolean eq =
-                        className.equals(other.className)
-                    && (   (id == null && other.id == null)
-                        || (id != null && id.equals(other.id))
-                       )
-                    && (   (styleClass == null && other.styleClass == null)
-                        || (styleClass != null && styleClass.containsAll(other.styleClass))
-                       );
-                return eq;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = className.hashCode();
-            hash = 31 * (hash + ((id == null || id.isEmpty()) ? 1231 : id.hashCode()));
-            hash = 31 * (hash + ((styleClass == null || styleClass.isEmpty()) ? 1237 : styleClass.hashCode()));
-            return hash;
-        }
-
-        @Override
-        public String toString() {
-            return "Key ["+className+", "+String.valueOf(id)+", "+String.valueOf(styleClass)+"]";
-        }
-
     }
+    
 
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/Stylesheet.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Stylesheet.java	Fri Sep 14 10:20:59 2012 -0700
@@ -84,6 +84,7 @@
 
         @Override
         protected void onChanged(Change<Rule> c) {
+            c.reset();
             while (c.next()) {
                 if (c.wasAdded()) {
                     for(Rule rule : c.getAddedSubList()) {
--- a/javafx-ui-common/src/javafx/scene/Node.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Fri Sep 14 10:20:59 2012 -0700
@@ -2147,7 +2147,7 @@
         //if (PerformanceTracker.isLoggingEnabled()) {
         //    PerformanceTracker.logEvent("Node.init for [{this}, id=\"{id}\"]");
         //}
-
+        styleHelper = new StyleHelper(this);
         setDirty();
         updateTreeVisible();
         //if (PerformanceTracker.isLoggingEnabled()) {
@@ -7464,11 +7464,11 @@
     @Deprecated // SB-dependency: RT-21206 has been filed to track this    
     public void impl_processCSS(StyleManager styleManager, boolean reapply) {
 
-        // Create a new StyleHelper either if I am told I need to reapply
+        // Match new styles if I am told I need to reapply
         // or if my own flag indicates I need to reapply
         if (reapply || (cssFlag == CSSFlags.REAPPLY)) {
 
-            styleHelper = styleManager.getStyleHelper(this);
+            styleHelper.setStyles(styleManager);
 
         } 
         
@@ -7478,7 +7478,7 @@
 
         // Transition to the new state
         if (styleHelper != null) {
-            styleHelper.transitionToState(this);
+            styleHelper.transitionToState();
         }
     }
     
@@ -7487,18 +7487,8 @@
      * A StyleHelper contains all the css styles for this node
      * and knows how to apply them when our state changes.
      */
-    private StyleHelper styleHelper;
+    private final StyleHelper styleHelper;
     
-    /**
-     * @treatAsPrivate implementation detail
-     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
-     */
-//    @Deprecated
-//    protected StyleHelper impl_createStyleHelper() {
-//        
-//        styleHelper = getScene().styleManager.getStyleHelper(this);
-//        return styleHelper;
-//    }
 
     /**
      * Get this nodes StyleHelper
--- a/javafx-ui-common/src/javafx/scene/Parent.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Parent.java	Fri Sep 14 10:20:59 2012 -0700
@@ -1076,6 +1076,9 @@
             final Scene scene = getScene();
             if (scene != null) {
 
+                // if stylesheets change, 
+                //    then this Parent needs a new StyleManager 
+                Parent.this.styleManager = null;
                 StyleManager sm = getStyleManager();
                 if (sm != null) sm.stylesheetsChanged(c);
                 
@@ -1108,19 +1111,21 @@
         final Scene scene = getScene();
         final boolean hasStylesheets = (getStylesheets().isEmpty() == false);
         
-        if (hasStylesheets == false || scene == null) {
+        if (scene == null) {
             
             styleManager = null;
             
-        } else if (styleManager == null) {            
+        } else if (styleManager == null) {
             
-            Parent parent = getParent();
-            StyleManager sm = null;
-            while (parent != null && (sm = parent.styleManager) == null) {
-                parent = parent.getParent();
-            }
-            if (sm == null) sm = scene.styleManager;
-            styleManager = StyleManager.createStyleManager(this, sm);
+            // My styleManager is my parent's styleManager, 
+            // unless I have stylesheets of my own. 
+            final Parent parent = getParent();
+            styleManager = 
+                (parent != null) ? parent.getStyleManager() : scene.styleManager;
+            
+            if (hasStylesheets) {                        
+                styleManager = StyleManager.createStyleManager(Parent.this, styleManager);            
+            } 
         }
         
         return styleManager;
@@ -1168,18 +1173,18 @@
      */
     @Deprecated
     @Override public void impl_processCSS(StyleManager styleManager, boolean reapply) {
-        
+
+        // Parent has its own StyleManager which is either adopted from 
+        // Scene or is created new if this Parent has its own stylesheets.
         final StyleManager parentStyleManager = getStyleManager();
-        final StyleManager relevantStyleManager = 
-                parentStyleManager != null ? parentStyleManager : styleManager; 
         
         // Determine whether we will need to reapply from here on down
         boolean flag = reapply || cssFlag == CSSFlags.REAPPLY;
         // Let the super implementation handle CSS for this node
-        super.impl_processCSS(relevantStyleManager, flag);
+        super.impl_processCSS(parentStyleManager, flag);
         // For each child, process CSS
         for (int i=0, max=children.size(); i<max; i++) {
-            children.get(i).impl_processCSS(relevantStyleManager, flag);
+            children.get(i).impl_processCSS(parentStyleManager, flag);
         }
     }
     
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Fri Sep 14 10:20:59 2012 -0700
@@ -103,7 +103,7 @@
         return smap;
     }
     
-    @Test @org.junit.Ignore
+    @Test @org.junit.Ignore("will not compile, no StyleHelper#create mehod")
     public void testStyleMapTracksChanges() {
 
         final List<Declaration> decls = new ArrayList<Declaration>();
@@ -136,25 +136,25 @@
         rect = new Rectangle(50,50) {
 
             // I'm bypassing StyleManager by creating StyleHelper directly. 
-            StyleHelper shelper = null;
+//            StyleHelper shelper = null;
                                    
             
-            @Override public StyleHelper impl_getStyleHelper() {
-                if (shelper == null) {
-                    // If no styleclass, then create an StyleHelper with no mappings.
-                    // Otherwise, create a StyleHelper matching the "rect" style class.
-                    if (getStyleClass().isEmpty()) {
-                        Map<StyleCacheKey, StyleCacheBucket> styleCache = 
-                            new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheBucket>();
-                        shelper = StyleHelper.create(rect, emptyMap, styleCache, 0, 0);
-                    } else  {
-                        Map<StyleCacheKey, StyleCacheBucket> styleCache = 
-                            new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheBucket>();
-                        shelper = StyleHelper.create(rect, styleMap, styleCache, 0, 0);
-                    }
-                }
-                return shelper;
-            }
+//            @Override public StyleHelper impl_getStyleHelper() {
+//                if (shelper == null) {
+//                    // If no styleclass, then create an StyleHelper with no mappings.
+//                    // Otherwise, create a StyleHelper matching the "rect" style class.
+//                    if (getStyleClass().isEmpty()) {
+//                        Map<StyleCacheKey, StyleCacheBucket> styleCache = 
+//                            new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheBucket>();
+//                        shelper = StyleHelper.create(rect, emptyMap, styleCache, 0, 0);
+//                    } else  {
+//                        Map<StyleCacheKey, StyleCacheBucket> styleCache = 
+//                            new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheBucket>();
+//                        shelper = StyleHelper.create(rect, styleMap, styleCache, 0, 0);
+//                    }
+//                }
+//                return shelper;
+//            }
         };
                 
         rect.getStyleClass().add("rect");
@@ -225,18 +225,18 @@
         group = new Group() {
 
             // I'm bypassing StyleManager by creating StyleHelper directly. 
-            StyleHelper shelper = null;
-                                               
-            @Override public void impl_processCSS(boolean reapply) {
-                if (shelper == null) {
-                    shelper = StyleHelper.create(text, rootStyleMap, styleCache, 0, 1);
-                };
-                shelper.transitionToState(group);
-            }
-            
-            @Override public StyleHelper impl_getStyleHelper() {
-                return shelper;
-            }            
+//            StyleHelper shelper = null;
+//                                               
+//            @Override public void impl_processCSS(boolean reapply) {
+//                if (shelper == null) {
+//                    shelper = StyleHelper.create(text, rootStyleMap, styleCache, 0, 1);
+//                };
+//                shelper.transitionToState(group);
+//            }
+//            
+//            @Override public StyleHelper impl_getStyleHelper() {
+//                return shelper;
+//            }            
         };
         group.getStyleClass().add("root");
         
@@ -271,24 +271,24 @@
         text = new Text("HelloWorld") {
 
             // I'm bypassing StyleManager by creating StyleHelper directly. 
-            StyleHelper shelper = null;
-            
-            @Override public void impl_processCSS(boolean reapply) {
-                if (reapply) {
-                    shelper = null;
-                    if (getStyleClass().isEmpty()) {
-                        shelper = StyleHelper.create(text, emptyMap, styleCache, 0, 2);
-                    } else  {
-                        shelper = StyleHelper.create(text, styleMap, styleCache, 0, 2);
-                    }
-                }
-                shelper.transitionToState(text);
-            }
-                                               
-            @Override public StyleHelper impl_getStyleHelper() {
-                return shelper;
-            }            
-            
+//            StyleHelper shelper = null;
+//            
+//            @Override public void impl_processCSS(boolean reapply) {
+//                if (reapply) {
+//                    shelper = null;
+//                    if (getStyleClass().isEmpty()) {
+//                        shelper = StyleHelper.create(text, emptyMap, styleCache, 0, 2);
+//                    } else  {
+//                        shelper = StyleHelper.create(text, styleMap, styleCache, 0, 2);
+//                    }
+//                }
+//                shelper.transitionToState(text);
+//            }
+//                                               
+//            @Override public StyleHelper impl_getStyleHelper() {
+//                return shelper;
+//            }            
+//            
         };
         
         group.getChildren().add(text);
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Fri Sep 14 10:20:59 2012 -0700
@@ -146,19 +146,6 @@
     }
 
     @Ignore @Test
-    public void testMightApply() {
-        System.out.println("mightApply");
-        String className = "";
-        String id = "";
-        List<String> styleClasses = null;
-        Rule instance = null;
-        boolean expResult = false;
-        boolean result = instance.mightApply(className, id, styleClasses);
-        assertEquals(expResult, result);
-        fail("The test case is a prototype.");
-    }
-
-    @Ignore @Test
     public void testApplies() {
         System.out.println("applies");
         Node node = null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/SelectorPartitioningTest.java	Fri Sep 14 10:20:59 2012 -0700
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.css;
+
+import com.sun.javafx.css.parser.CSSParser;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javafx.scene.paint.Color;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Before;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SelectorPartitioningTest {
+    
+    public SelectorPartitioningTest(final Data data) {
+        this.data = data;
+        this.instance = new SelectorPartitioning();
+    }
+    private final Data data;
+    private final SelectorPartitioning instance;
+
+    private static class Data {
+        final Color  color;
+        final String stylesheetText;
+        
+        Data(Color color, String stylesheetText) {
+            this.color = color;
+            this.stylesheetText = stylesheetText;
+        }
+        
+    }
+    
+    private static class SimpleData extends Data {
+        
+        final SimpleSelector selector;
+        final boolean matches;
+        
+        SimpleData(String type, String styleClass, String id, Color color) {
+            this(type, styleClass, id, color, true);
+        }
+        SimpleData(String type, String styleClass, String id, Color color, boolean matches) {
+            super(color, (new StringBuilder()
+                    .append((type != null ? type : "*"))
+                    .append((styleClass != null ? ".".concat(styleClass) : ""))
+                    .append((id != null ? "#".concat(id) : ""))
+                    .append("{-fx-fill: rgb(")
+                    .append(Double.valueOf(color.getRed()*255).intValue()).append(",")
+                    .append(Double.valueOf(color.getGreen()*255).intValue()).append(",")
+                    .append(Double.valueOf(color.getBlue()*255).intValue()).append(");}")
+                ).toString());
+            List<String> styleClasses = 
+                styleClass != null ? Arrays.asList(styleClass.split("\\.")) : null;
+            this.selector = 
+                new SimpleSelector(type, styleClasses, null, id);            
+            this.matches = matches;
+        }
+    }
+    
+    private static class ComplexData extends Data {
+
+        final SimpleData[] data;
+        final SimpleSelector selector;
+        final int matches;
+        
+        ComplexData(SimpleSelector selector, SimpleData... data) {
+            super(Color.TRANSPARENT, combineStylesheets(data));
+            this.data = data;
+            this.selector = selector;
+            int n = 0;
+            for (SimpleData datum : data) {
+                if (datum.matches) n += 1;
+            }
+            this.matches = n;
+        }
+        
+        static String combineStylesheets(Data... data) {
+            StringBuilder buf = new StringBuilder();
+            for (Data datum : data) {
+                buf.append(datum.stylesheetText).append('\n');
+            }
+            return buf.toString();
+        }
+    }
+    
+    
+    @Parameters
+    public static Collection data() {
+
+        int red = 0;
+        int green = 0;
+        int blue = 0;
+        return Arrays.asList(new Object[] {
+            /* selector = * */
+            new Object[] {new SimpleData("*", null, null, Color.rgb(red += 10, 0, 0))},
+            /* selector = A */
+            new Object[] {new SimpleData("A", null, null, Color.rgb(red += 10, 0, 0))},
+            /* selector = * A.b */
+            new Object[] {new SimpleData("A", "b", null, Color.rgb(red += 10, 0, 0))},
+            /* selector = A#c */
+            new Object[] {new SimpleData("A", null, "c", Color.rgb(red += 10, 0, 0))},
+            /* selector = A.b#c */
+            new Object[] {new SimpleData("A", "b", "c", Color.rgb(red += 10, 0, 0))},
+            /* selector = *.b */
+            new Object[] {new SimpleData("*", "b", null, Color.rgb(red += 10, 0, 0))},
+            /* selector = *#c */
+            new Object[] {new SimpleData("*", null, "c", Color.rgb(red += 10, 0, 0))},
+            /* selector = *.b#c */
+            new Object[] {new SimpleData("*", "b", "c", Color.rgb(red += 10, 0, 0))},
+            
+            new Object[] {
+                new ComplexData(
+                    (SimpleSelector)Selector.createSelector("*.b"),
+                    new SimpleData("*", "b", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "c", null, Color.rgb(0, green += 10, 0), false),
+                    new SimpleData("*", "b.c", null, Color.rgb(0, green += 10, 0), false)
+                )},
+            new Object[] {
+                new ComplexData(
+                    (SimpleSelector)Selector.createSelector("*.b.c"),
+                    new SimpleData("*", "b", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "c", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "b.c", null, Color.rgb(0, green += 10, 0), true)
+                )},
+            new Object[] {
+                new ComplexData(
+                    (SimpleSelector)Selector.createSelector("A.b"),
+                    new SimpleData("*", "b", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("A", "b", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", null, null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "c", null, Color.rgb(0, green += 10, 0), false),
+                    new SimpleData("*", "b.c", null, Color.rgb(0, green += 10, 0), false)
+                )},
+            new Object[] {
+                new ComplexData(
+                    (SimpleSelector)Selector.createSelector("A.c"),
+                    new SimpleData("*", "b", null, Color.rgb(0, green += 10, 0), false),
+                    new SimpleData("A", "b", null, Color.rgb(0, green += 10, 0), false),
+                    new SimpleData("*", null, null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "c", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "b.c", null, Color.rgb(0, green += 10, 0), false)
+                )},
+            new Object[] {
+                new ComplexData(
+                    (SimpleSelector)Selector.createSelector("A.b.c"),
+                    new SimpleData("*", "b", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("A", "b", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", null, null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "c", null, Color.rgb(0, green += 10, 0), true),
+                    new SimpleData("*", "b.c", null, Color.rgb(0, green += 10, 0), true)
+                )}
+        });
+    }    
+
+    @Test
+    public void testSelectorPartitionAndMatch() {
+
+        Stylesheet stylesheet = 
+                CSSParser.getInstance().parse(data.stylesheetText);
+                
+        for (Rule rule : stylesheet.getRules()) {
+            for (Selector selector : rule.selectors) {
+                instance.partition(selector, rule);                
+            }
+        }
+        
+        if (data instanceof SimpleData) {
+            testWithSimpleData((SimpleData)data, stylesheet);            
+        } else {
+            testWithComplexData((ComplexData)data, stylesheet);
+        }
+    }
+    
+    private void testWithSimpleData(SimpleData simpleData, Stylesheet stylesheet) {
+                
+        SimpleSelector simple = simpleData.selector;
+        
+        List<Rule> matched = instance.match(simple.getId(), simple.getName(), simple.getStyleClassMasks());
+        
+        assertEquals(1,matched.size());
+        Rule rule = matched.get(0);
+        
+        assertEquals(1,rule.declarations.size());
+        Declaration decl = rule.declarations.get(0);
+        
+        assertEquals("-fx-fill", decl.property);
+        
+        Color color = (Color)decl.parsedValue.convert(null);
+        
+        assertEquals(simpleData.selector.toString(), data.color.getRed(), color.getRed(), 0.00001);
+        assertEquals(simpleData.selector.toString(), data.color.getGreen(), color.getGreen(), 0.00001);
+        assertEquals(simpleData.selector.toString(), data.color.getBlue(), color.getBlue(), 0.00001);
+                
+    }
+    
+    private void testWithComplexData(ComplexData complexData, Stylesheet stylesheet) {
+                
+        SimpleSelector simple = complexData.selector;
+        
+        List<Rule> matched = instance.match(simple.getId(), simple.getName(), simple.getStyleClassMasks());
+        assertEquals(complexData.matches, matched.size());
+        
+        for(Rule rule : matched) {
+            Selector s1 = rule.selectors.get(0);
+            for (SimpleData datum : complexData.data) {
+                Selector s2 = (SimpleSelector)datum.selector;
+                if (s1.equals(s2)) {
+                    assertTrue(s1.toString() + " != " + s2.toString(), datum.matches);
+                }
+            }
+        }
+
+    }
+    
+}
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/StyleablePropertyTest.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/StyleablePropertyTest.java	Fri Sep 14 10:20:59 2012 -0700
@@ -276,6 +276,9 @@
     }
     
     Group createGroup(final CascadingStyle... styles ) {
+        
+        // TBD: can't execute this code because there is no StyleHelper.create method
+        assert false : "caller should be @Ignored";
     
         final List<CascadingStyle> cascadingStyles = new ArrayList<CascadingStyle>();
         Collections.addAll(cascadingStyles, styles);
@@ -287,18 +290,18 @@
         
         final Group group = new Group() {
             // I'm bypassing StyleManager by creating StyleHelper directly. 
-            StyleHelper shelper = null;
-            
-            @Override public void impl_processCSS(boolean reapply) {
-                if (reapply) {
-                    shelper = StyleHelper.create(this, styleMap, styleCache, 0, 2);
-                }
-                shelper.transitionToState(this);
-            }
-                                               
-            @Override public StyleHelper impl_getStyleHelper() {
-                return shelper;
-            }            
+//            StyleHelper shelper = null;
+//            
+//            @Override public void impl_processCSS(boolean reapply) {
+//                if (reapply) {
+//                    shelper = StyleHelper.create(this, styleMap, styleCache, 0, 2);
+//                }
+//                shelper.transitionToState(this);
+//            }
+//                                               
+//            @Override public StyleHelper impl_getStyleHelper() {
+//                return shelper;
+//            }            
             
         };
         group.getStyleClass().add("root");
@@ -307,7 +310,10 @@
     }
     
     Rectangle createRectangle(final CascadingStyle... styles ) {
-    
+
+        // TBD: can't execute this code because there is no StyleHelper.create method
+        assert false : "caller should be @Ignored";
+            
         final List<CascadingStyle> cascadingStyles = new ArrayList<CascadingStyle>();
         Collections.addAll(cascadingStyles, styles);
         final  Map<String, List<CascadingStyle>> styleMap = 
@@ -317,18 +323,18 @@
         
         Rectangle rectangle = new Rectangle() {
             // I'm bypassing StyleManager by creating StyleHelper directly. 
-            StyleHelper shelper = null;
-            
-            @Override public void impl_processCSS(boolean reapply) {
-                if (reapply) {
-                    shelper = StyleHelper.create(this, styleMap, styleCache, 0, 2);
-                }
-                shelper.transitionToState(this);
-            }
-                                               
-            @Override public StyleHelper impl_getStyleHelper() {
-                return shelper;
-            }            
+//            StyleHelper shelper = null;
+//            
+//            @Override public void impl_processCSS(boolean reapply) {
+//                if (reapply) {
+//                    shelper = StyleHelper.create(this, styleMap, styleCache, 0, 2);
+//                }
+//                shelper.transitionToState(this);
+//            }
+//                                               
+//            @Override public StyleHelper impl_getStyleHelper() {
+//                return shelper;
+//            }            
                                     
         };
         rectangle.getStyleClass().add("rect");
@@ -337,7 +343,7 @@
     }
 
     static class RectangleWithFont extends Rectangle {
-    
+                
         final List<CascadingStyle> cascadingStyles = new ArrayList<CascadingStyle>();
         final  Map<String, List<CascadingStyle>> styleMap = 
                 Node_cssStyleMap_Test.createStyleMap(cascadingStyles);
@@ -351,18 +357,21 @@
             super();
             getStyleClass().add("rect");
             Collections.addAll(cascadingStyles, styles);
+            
+            assert false : "caller should be @Ignored";
+            // TBD: can't execute this code because there is no StyleHelper.create method
         }    
         
-            @Override public void impl_processCSS(boolean reapply) {
-                if (reapply) {
-                    shelper = StyleHelper.create(this, styleMap, styleCache, 0, 2);
-                }
-                shelper.transitionToState(this);
-            }
-                                               
-            @Override public StyleHelper impl_getStyleHelper() {
-                return shelper;
-            }            
+//            @Override public void impl_processCSS(boolean reapply) {
+//                if (reapply) {
+//                    shelper = StyleHelper.create(this, styleMap, styleCache, 0, 2);
+//                }
+//                shelper.transitionToState(this);
+//            }
+//                                               
+//            @Override public StyleHelper impl_getStyleHelper() {
+//                return shelper;
+//            }            
             
         ObjectProperty<Font> font = new StyleableObjectProperty<Font>() {
 
@@ -988,7 +997,7 @@
     } 
 
 
-    @Test
+    @Test @org.junit.Ignore("uses createGroup which, in turn, relies on a method that is no longer available")
     public void testGetMatchingStylesShouldNotReturnInlineAncestorPropertyIfNotInherited() {
 
         
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ComboBoxListViewSkin.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ComboBoxListViewSkin.java	Fri Sep 14 10:20:59 2012 -0700
@@ -509,13 +509,28 @@
                 return getListViewPrefHeight();
             }
             
+            @Override 
+            public void impl_processCSS(com.sun.javafx.css.StyleManager styleManger, boolean reapply) {
+                
+                //
+                // If the popup doesn't have an owner window, then css won't 
+                // have any stylesheets for the popup yet since the popup gets
+                // the stylesheets from the scene of the owner window.
+                //
+                final PopupControl popup = getPopup();
+                if (popup.getOwnerWindow() == null) return;
+                
+                super.impl_processCSS(styleManger, reapply);
+            }
+            
             private void doCSSCheck() {
-                Parent parent = getPopup().getScene().getRoot();
-                if ((isFirstSizeCalculation || getSkin() == null) && parent.getScene() != null) {
+                final PopupControl popup = getPopup();
+                if ((isFirstSizeCalculation || getSkin() == null) && popup.getOwnerWindow() != null) {
                     // if the skin is null, it means that the css related to the
                     // listview skin hasn't been loaded yet, so we force it here.
                     // This ensures the combobox button is the correct width
                     // when it is first displayed, before the listview is shown.
+                    final Parent parent = getPopup().getScene().getRoot();
                     parent.impl_processCSS(true);
                     isFirstSizeCalculation = false;
                 }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Fri Sep 14 10:20:59 2012 -0700
@@ -51,6 +51,7 @@
 import javafx.scene.control.IndexRange;
 import javafx.scene.control.TextField;
 import javafx.scene.input.MouseEvent;
+import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
 import javafx.scene.shape.Path;
 import javafx.scene.shape.PathElement;
@@ -309,7 +310,7 @@
                 getSkinnable().requestLayout();
             }
         });
-        
+
         registerChangeListener(textField.prefColumnCountProperty(), "prefColumnCount");
         if (textField.isFocused()) setCaretAnimating(true);
 
@@ -324,15 +325,24 @@
         });
 
         usePromptText = new BooleanBinding() {
-            { bind(textField.textProperty(), textField.promptTextProperty()); }
+            { bind(textField.textProperty(),
+                   textField.promptTextProperty(),
+                   promptTextFill); }
             @Override protected boolean computeValue() {
                 String txt = textField.getText();
                 String promptTxt = textField.getPromptText();
                 return ((txt == null || txt.isEmpty()) &&
-                        promptTxt != null && !promptTxt.isEmpty());
+                        promptTxt != null && !promptTxt.isEmpty() &&
+                        !promptTextFill.get().equals(Color.TRANSPARENT));
             }
         };
 
+        promptTextFill.addListener(new InvalidationListener() {
+            @Override public void invalidated(Observable observable) {
+                updateTextPos();
+            }
+        });
+
         textField.textProperty().addListener(new InvalidationListener() {
             @Override public void invalidated(Observable observable) {
                 if (!getBehavior().isEditing()) {
@@ -435,7 +445,6 @@
         promptNode.visibleProperty().bind(usePromptText);
         promptNode.fontProperty().bind(font);
         promptNode.xProperty().bind(textLeft);
-        promptNode.layoutXProperty().set(0.0);
         promptNode.textProperty().bind(getSkinnable().promptTextProperty());
         promptNode.fillProperty().bind(promptTextFill);
         updateSelection();
@@ -502,7 +511,7 @@
 
     @Override
     public double getBaselineOffset() {
-        FontMetrics fontMetrics = super.fontMetrics.get();       
+        FontMetrics fontMetrics = super.fontMetrics.get();
         return getInsets().getTop() + fontMetrics.getAscent();
     }
 
@@ -510,17 +519,29 @@
         switch (getSkinnable().getAlignment().getHpos()) {
           case CENTER:
             double midPoint = (textRight.get() - textLeft.get()) / 2;
-            textTranslateX.set(midPoint - textNode.getLayoutBounds().getWidth() / 2);
+            if (usePromptText.get()) {
+                promptNode.setLayoutX(midPoint - promptNode.getLayoutBounds().getWidth() / 2);
+                textTranslateX.set(promptNode.getLayoutX());
+            } else {
+                textTranslateX.set(midPoint - textNode.getLayoutBounds().getWidth() / 2);
+            }
             break;
 
           case RIGHT:
             textTranslateX.set(textRight.get() - textNode.getLayoutBounds().getWidth() -
                                caretWidth / 2 - 5);
+            if (usePromptText.get()) {
+                promptNode.setLayoutX(textRight.get() - promptNode.getLayoutBounds().getWidth() -
+                                      caretWidth / 2 - 5);
+            }
             break;
 
           case LEFT:
           default:
             textTranslateX.set(caretWidth / 2);
+            if (usePromptText.get()) {
+                promptNode.layoutXProperty().set(caretWidth / 2);
+            }
         }
     }
 
--- a/javafx-ui-controls/src/javafx/scene/control/Control.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/control/Control.java	Fri Sep 14 10:20:59 2012 -0700
@@ -738,12 +738,12 @@
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
     @Deprecated
-    @Override public void impl_processCSS(boolean reapply) {
+    @Override public void impl_processCSS(StyleManager styleManager, boolean reapply) {
         if (reapply && getUserAgentStylesheet() != null) {
-            StyleManager.getStyleManager(getScene()).addUserAgentStylesheet(getUserAgentStylesheet());
+            styleManager.addUserAgentStylesheet(getUserAgentStylesheet());
         }
 
-        super.impl_processCSS(reapply);
+        super.impl_processCSS(styleManager, reapply);
 
         if (getSkin() == null) {
             final String msg = 
--- a/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledTextTest.java	Thu Sep 13 21:56:27 2012 -0700
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledTextTest.java	Fri Sep 14 10:20:59 2012 -0700
@@ -293,7 +293,8 @@
                 };
         label.setTextFill(Color.YELLOW);
         stage.setScene(scene = new Scene(label));
-        label.impl_processCSS(true);
+        stage.show();
+//        label.impl_processCSS(true);
         labeledText = ((com.sun.javafx.scene.control.skin.LabeledSkinBase)label.getSkin()).text; 
         assertEquals(Color.YELLOW, labeledText.getFill());
     }
@@ -310,7 +311,8 @@
         Font font = Font.font("Amble", 30);
         label.setFont(font);
         stage.setScene(scene = new Scene(label));
-        label.impl_processCSS(true);
+        stage.show();
+//        label.impl_processCSS(true);
         labeledText = ((com.sun.javafx.scene.control.skin.LabeledSkinBase)label.getSkin()).text; 
         assertEquals(font, labeledText.getFont());
     }
@@ -326,7 +328,8 @@
                 };
         label.setTextAlignment(TextAlignment.JUSTIFY);
         stage.setScene(scene = new Scene(label));
-        label.impl_processCSS(true);
+        stage.show();
+//        label.impl_processCSS(true);
         labeledText = ((com.sun.javafx.scene.control.skin.LabeledSkinBase)label.getSkin()).text; 
         assertEquals(TextAlignment.JUSTIFY, labeledText.getTextAlignment());
     }
@@ -342,7 +345,8 @@
                 };
         label.setUnderline(true);
         stage.setScene(scene = new Scene(label));
-        label.impl_processCSS(true);
+        stage.show();
+//        label.impl_processCSS(true);
         labeledText = ((com.sun.javafx.scene.control.skin.LabeledSkinBase)label.getSkin()).text; 
         assertTrue(labeledText.isUnderline());
     }