changeset 1799:ea00b638cdd6 8.0-b60

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/MASTER/rt
author leifs
date Tue, 09 Oct 2012 13:07:14 -0700
parents b06b91a885a0 c0aff81b30ad
children 7f6a99c842fd 19bdbf3b30ee 988f6f79107b
files javafx-ui-common/test/unit/javafx/scene/layout/BorderImageSlicesTest.java javafx-ui-common/test/unit/javafx/scene/layout/BorderImageSlices_builder_Test.java
diffstat 20 files changed, 393 insertions(+), 583 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/com/sun/javafx/css/CascadingStyle.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/CascadingStyle.java	Tue Oct 09 13:07:14 2012 -0700
@@ -25,6 +25,7 @@
 
 package com.sun.javafx.css;
 
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -40,7 +41,7 @@
     }
     
     /** State variables, like "hover" or "pressed" */
-    private final List<String> pseudoclasses;
+    private long pseudoclasses;
 
     /* specificity of the rule that matched */
     private final int specificity;
@@ -55,12 +56,9 @@
     private final boolean skinProp;
 
     // internal to Style
-    private int hash = -1;
-
-    // internal to Style
     static private Set<String> strSet = new HashSet<String>();
 
-    CascadingStyle(final Style style, final List<String> pseudoclasses, 
+    CascadingStyle(final Style style, long pseudoclasses, 
             final int specificity, final int ordinal) {
         this.style = style;
         this.pseudoclasses = pseudoclasses;
@@ -114,24 +112,8 @@
             return false;
         }
         
-        // if either pseudoclass is null, both have to be null
-        if (pseudoclasses == null && other.pseudoclasses == null) {
-            return true;
-        } else if (pseudoclasses == null || other.pseudoclasses == null) {
-            return false;
-        }
-
-        if (pseudoclasses.size() != other.pseudoclasses.size()) 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=pseudoclasses.size(); n<max; n++)
-            strSet.add(other.pseudoclasses.get(n));
-        for (int n=0, max=other.pseudoclasses.size(); n<max; n++) {
-            if (! strSet.contains(other.pseudoclasses.get(n))) return false;
-        }
-        return true;
+        return ((pseudoclasses & other.pseudoclasses) ==  pseudoclasses);
 
     }
 
@@ -139,15 +121,12 @@
      * Hash on property and pseudoclasses since
      * obj1.hashCode() should equal obj2.hashCode() if obj1.equals(obj2)
      */
-    @Override public int hashCode() {
-        if (hash == -1) {
-            hash = super.hashCode();
-            if (pseudoclasses != null) {
-                for (int n=0, max=pseudoclasses.size(); n<max; n++) {
-                    hash = 31*hash + pseudoclasses.get(n).hashCode();
-                }
-            }
-        }
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        final String property = getProperty();
+        hash = 47 * hash + (property != null ? property.hashCode() : 0);
+        hash = 47 * hash + (int) (this.pseudoclasses ^ (this.pseudoclasses >>> 32));
         return hash;
     }
 
--- a/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Tue Oct 09 13:07:14 2012 -0700
@@ -121,13 +121,10 @@
             final Match ancestorMatch = matches(parent, index-1);
             if (ancestorMatch != null) {
 
-                List<String> ancestorPseudoclasses = ancestorMatch.pseudoclasses;
-                List<String> descendantPseudoclasses = descendantMatch.pseudoclasses;
-                List<String> pseudoclasses = new ArrayList<String>();
-                pseudoclasses.addAll(ancestorMatch.pseudoclasses);
-                pseudoclasses.addAll(descendantMatch.pseudoclasses);
-
-                return new Match(this, pseudoclasses,
+                long ancestorPseudoclasses = ancestorMatch.pseudoclasses;
+                long descendantPseudoclasses = descendantMatch.pseudoclasses;
+                return new Match(this, 
+                        ancestorPseudoclasses | descendantPseudoclasses,
                         ancestorMatch.idCount + descendantMatch.idCount,
                         ancestorMatch.styleClassCount + descendantMatch.styleClassCount);
             }
@@ -147,16 +144,34 @@
 
     @Override
     public boolean applies(final Node node) {
-        return applies(node, selectors.size()-1);
+        return applies(node, selectors.size()-1, null, 0);
     }
 
-    private boolean applies(final Node node, final int index) {
+    @Override
+    boolean applies(final Node node, long[] pseudoclassBits, int bit) {
+        
+        // 
+        // We only care about pseudoclassBits if the selector applies. But in
+        // the case of a compound selector, we don't know whether it applies
+        // until all the selectors have been checked (in the worse case). So
+        // the setting of pseudoclassBits has to be deferred until we know
+        // that this compound selector applies. So we'll send a clone and if 
+        // the compound selector applies, we can just copy the bits back.        
+        final long[] tempBits = pseudoclassBits != null ? pseudoclassBits.clone() : null;
+        final boolean applies = applies(node, selectors.size()-1, tempBits, bit);
+        if (applies && (tempBits != null)) {
+            System.arraycopy(tempBits, 0, pseudoclassBits, 0, pseudoclassBits.length);
+        }
+        return applies;
+    }
+
+    private boolean applies(final Node node, final int index, long[] pseudoclassBits, int bit) {
         // If the index is < 0 then we know we don't apply
         if (index < 0) return false;
 
         // Simply check the selector associated with this index and see if it
         // applies to the Node
-        if (! selectors.get(index).applies(node)) return false;
+        if (! selectors.get(index).applies(node, pseudoclassBits, bit)) return false;
 
         // If there are no more selectors to check (ie: index == 0) then we
         // know we know we apply
@@ -176,11 +191,11 @@
             if (parent == null) return false;
             // If this call succeeds, then all preceding selectors will have
             // matched due to the recursive nature of the call
-            return applies(parent, index - 1);
+            return applies(parent, index - 1, pseudoclassBits, ++bit);
         } else {
              Node parent = node.getParent();
             while (parent != null) {
-                boolean answer = applies(parent, index - 1);
+                boolean answer = applies(parent, index - 1, pseudoclassBits, ++bit);
                 // If a call to stateMatches succeeded, then we know that
                 // all preceding selectors will have also matched.
                 if (answer) return true;
--- a/javafx-ui-common/src/com/sun/javafx/css/Match.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Match.java	Tue Oct 09 13:07:14 2012 -0700
@@ -25,6 +25,7 @@
 package com.sun.javafx.css;
 
 import java.util.List;
+import javafx.scene.Node;
 
 /**
  * Used by {@link Rule} to determine whether or not the rule applies to a
@@ -36,30 +37,28 @@
 final class Match implements Comparable {
 
     final Selector selector;
-    final List<String> pseudoclasses;
+    final long pseudoclasses;
     final int idCount;
     final int styleClassCount;
-
+    
+    List<Match> descendantMatches;
+    
     // CSS3 spec gives weight to id count, then style class count,
     // then pseudoclass count, and finally matching types (i.e., java name count)
     final int specificity;
 
-    public Match(final Selector selector, final List<String> pseudoclasses,
+    Match(final Selector selector, long pseudoclasses,
             final int idCount, final int styleClassCount) {
         assert selector != null;
         this.selector = selector;
-        this.pseudoclasses = pseudoclasses;
         this.idCount = idCount;
         this.styleClassCount = styleClassCount;
-        final int nPseudoclasses = (pseudoclasses != null) ?  pseudoclasses.size() : 0;
+        this.pseudoclasses = pseudoclasses;
+        int nPseudoclasses = Long.bitCount(pseudoclasses);
+        
         specificity = (idCount << 8) | (styleClassCount << 4) | nPseudoclasses;
     }
-
-    private Match() {
-        this(null, null, 0, 0);
-        assert false : "null arg ctor \'Match\' called";
-    }
-    
+        
     @Override
     public int compareTo(Object o) {
         Match m = (Match)o;
@@ -70,7 +69,7 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append(selector);
-        for (String s : pseudoclasses) {
+        for(String s : StyleManager.getPseudoclassStrings(pseudoclasses)) {
             sb.append(":");
             sb.append(s);
         }
--- a/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Tue Oct 09 13:07:14 2012 -0700
@@ -135,10 +135,10 @@
         return matches;
     }
 
-    public boolean applies(Node node) {
+    boolean applies(Node node, long[] pseudoclassBits) {
         for (int i = 0; i < selectors.size(); i++) {
             Selector sel = selectors.get(i);
-            if (sel.applies(node)) return true;
+            if (sel.applies(node, pseudoclassBits, 0)) return true;
         }
         return false;
     }
--- a/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Tue Oct 09 13:07:14 2012 -0700
@@ -63,6 +63,9 @@
     // same as the matches method expect return true/false rather than a match
     public abstract boolean applies(Node node);
     
+    // same as applies, but will return pseudoclass state that it finds along the way
+    abstract boolean applies(Node node, long[] pseudoclassBits, int bit);
+    
     /**
      * Determines whether the current state of the node and its parents
      * matches the pseudoclasses defined (if any) for this selector.
--- a/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Tue Oct 09 13:07:14 2012 -0700
@@ -101,7 +101,7 @@
             final String styleClass = styleClasses.get(n);
             final long m = getStyleClassMask(styleClass);
             final long element = (m & ~VALUE_MASK);
-            final int  index = (int)(element >> VALUE_BITS);
+            final int  index = (int)(element >>> VALUE_BITS);
             // need to grow?
             if (index >= mask.length) {
                 final long[] temp = new long[index+1];
@@ -169,15 +169,6 @@
     /** 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
-     */
-    public List<String> getPseudoclasses() {
-        return pseudoclasses;
-    }
-    
-
     final private String id;
     /*
      * @return The value of the selector id, which may be an empty string.
@@ -188,7 +179,18 @@
     
     // a mask of bits corresponding to the pseudoclasses
     final private long pclassMask;
+    
+    long getPseudoclassMask() {
+        return pclassMask;
+    }
 
+    /**
+     * @return Immutable List&lt;String&gt; of pseudo-classes of the selector
+     */
+    public List<String> getPseudoclasses() {
+        return StyleManager.getPseudoclassStrings(pclassMask);
+    }
+        
     // true if name is not a wildcard
     final private boolean matchOnName;
 
@@ -213,11 +215,10 @@
                 : new long[0];
         this.matchOnStyleClass = (this.styleClassMasks.length > 0);
 
-        this.pseudoclasses = 
+        this.pclassMask = 
                 (pseudoclasses != null) 
-                ? Collections.unmodifiableList(pseudoclasses)  
-                : Collections.EMPTY_LIST;
-        pclassMask = StyleManager.getPseudoclassMask(pseudoclasses);
+                ? StyleManager.getPseudoclassMask(pseudoclasses)
+                : 0;
 
         this.id = id == null ? "" : id;
         // if id is not null and not empty, then match needs to check id
@@ -242,15 +243,6 @@
         }
         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;
@@ -273,7 +265,7 @@
             for (int n=0; n<styleClassMasks.length; n++) {
                 styleClassCount += Long.bitCount(styleClassMasks[n] & VALUE_MASK);
             }
-            return new Match(this, pseudoclasses, idCount, styleClassCount);
+            return new Match(this, pclassMask, idCount, styleClassCount);
         }
         return null;
     }
@@ -281,7 +273,7 @@
     @Override 
     Match matches(final Scene scene) {
         // Scene should match wildcard or specific java class name only.
-        if (!matchOnStyleClass && !matchOnId && pseudoclasses.isEmpty()) {
+        if (!matchOnStyleClass && !matchOnId && pclassMask == 0) {
 
             final String className = scene.getClass().getName();
             final boolean classMatch =
@@ -290,7 +282,7 @@
             if (classMatch) {
                 // we know idCount and styleClassCount are zero from
                 // the condition for entering the outer block
-                return new Match(this, pseudoclasses, 0, 0 );
+                return new Match(this, pclassMask, 0, 0 );
             }
         }
         return null;
@@ -306,7 +298,10 @@
         // 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(selector.id);
+            boolean idMatch = 
+                    selector.matchOnId 
+                    ? id.equals(selector.id) 
+                    : false;
             if (!idMatch) return false;
         }
 
@@ -319,12 +314,38 @@
         }
 
         if (matchOnStyleClass) {
-            boolean styleClassMatch = matchStyleClasses(selector.styleClassMasks);                
+            boolean styleClassMatch = 
+                    selector.matchOnStyleClass 
+                    ? matchStyleClasses(selector.styleClassMasks) 
+                    : false;
             if (!styleClassMatch) return false;
         }
+        
         return true;
     }
+    
+    @Override 
+    boolean applies(Node node, long[] pseudoclassBits, int bit) {
 
+        final boolean applies = applies(node);
+        //
+        // We only need the pseudoclassBits if the selector applies to the node.
+        // 
+        assert(pseudoclassBits == null || bit < pseudoclassBits.length);
+        if (applies && pseudoclassBits != null && bit < pseudoclassBits.length) {
+            final long mask = pseudoclassBits[bit] | this.pclassMask;
+            pseudoclassBits[bit] = mask;
+        }
+        return applies;
+    }
+
+    boolean mightApply(final String className, final String id, long[] 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);
@@ -376,7 +397,7 @@
       * return true if seq1 is a subset of seq2. That is, all the strings
       * in seq1 are contained in seq2
       */
-    boolean isSubsetOf(long[] seq1, long[] seq2) {
+    static 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;
@@ -389,7 +410,12 @@
 
         // is [foo bar] a subset of [foo bar bang]?
         for (int n=0, max=seq1.length; n<max; n++) {
-            if ((seq1[n] & seq2[n]) != seq1[n]) return false;
+  
+            // if ((seq1[n] & seq2[n]) != seq1[n]) return false;
+            // is slower than the following... 
+            final long m1 = seq1[n];
+            final long m2 = m1 & seq2[n];
+            if (m1 != m2) return false;
         }
         return true;
 
@@ -450,6 +476,7 @@
             sbuf.append('#');
             sbuf.append(id);
         }
+        List<String> pseudoclasses = getPseudoclasses();
         for (int n=0; n<pseudoclasses.size(); n++) {
             sbuf.append(':');
             sbuf.append(pseudoclasses.get(n));
@@ -466,6 +493,7 @@
         os.writeShort(styleClasses.size());
         for (String sc  : styleClasses) os.writeShort(stringStore.addString(sc));
         os.writeShort(stringStore.addString(id));
+        List<String> pseudoclasses = getPseudoclasses();
         os.writeShort(pseudoclasses.size());
         for (String p : pseudoclasses)  os.writeShort(stringStore.addString(p));
     }
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Tue Oct 09 13:07:14 2012 -0700
@@ -35,7 +35,6 @@
 import java.util.Map.Entry;
 import javafx.beans.value.WritableValue;
 import javafx.scene.Node;
-import javafx.scene.Scene;
 import javafx.scene.text.Font;
 import javafx.scene.text.FontPosture;
 import javafx.scene.text.FontWeight;
@@ -45,7 +44,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;
+import javafx.scene.Parent;
 
 /**
  * The StyleHelper is a helper class used for applying CSS information to Nodes.
@@ -92,27 +91,11 @@
         this.localStyleCache = null;
         this.pseudoclassStateMask = 0;
         this.fontProp = null;
+        this.transitionStates = null;
         
         // styleManager can be null if  
         if (styleManager == null) return;
-        
-        StyleManager.StyleMap styleMap = styleManager != null
-                ? styleManager.findMatchingStyles(node, this.getSimpleSelector())
-                : null;
 
-        
-        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()) {                
-                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;
@@ -132,16 +115,32 @@
         // fetched using only those pseudoclasses that matter.
         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);
+        final StyleManager.StyleMap styleMap = styleManager != null
+                ? styleManager.findMatchingStyles(node, this.getSimpleSelector(), pclassMasks)
+                : null;
+
+        
+        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()) {                
+                return;
             }
         }
         
+        this.smapRef = new WeakReference<Map<String, List<CascadingStyle>>>(smap);
+
+        this.pseudoclassStateMask = pclassMasks[0];
+        
+        parent = node.getParent();
+        for(int n=1; n<depth; n++) {
+            final StyleHelper parentHelper = parent.impl_getStyleHelper();
+            parentHelper.pseudoclassStateMask = parentHelper.pseudoclassStateMask | pclassMasks[n];
+            parent = parent.getParent();
+        } 
+        
         // TODO: move initialization of localStyleCache somewhere else.
         //       It should not be hidden down here. Maybe to getCacheEntry
         this.localStyleCache = new StyleCacheBucket(pclassMasks);
@@ -178,9 +177,6 @@
             }
         }        
         
-        if (LOGGER.isLoggable(PlatformLogger.FINE)) {
-            LOGGER.fine(node + " " + key);
-        }
     }
 
     private long key;
@@ -278,51 +274,6 @@
         }
         
     }
-    
-    //
-    // 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;
-        }
-    }
         
     /**
      * There should only ever be one instance of a StyleCache for a given
@@ -515,28 +466,6 @@
         return smap;
     }
     
-    /**
-     * 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 example, your stylesheet might have:
-     * <pre><code>
-     * .button { ... }
-     * .button:hover { ... }
-     * .button *.label { text-fill: black }
-     * .button:hover *.label { text-fill: blue }
-     * </code></pre>
-     * In this case, the first 2 rules apply to the Button itself, but the
-     * second two rules apply to the label within a Button. When the hover
-     * changes on the Button, however, we must mark the Button as needing
-     * an UPDATE. StyleHelper though only contains styles for the first two
-     * rules for Button. The pseudoclassStateMask would in this case have
-     * only a single bit set for "hover". In this way the StyleHelper associated
-     * with the Button would know whether a change to "hover" requires the
-     * button and all children to be update. Other pseudoclass state changes
-     * that are not in this hash set are ignored.
-     */
-    private long pseudoclassStateMask;
-
     /** The node's font property, if there is one */
     private WritableValue fontProp;
 
@@ -556,10 +485,11 @@
         if (simpleSelector == null) {
 
             final String name = node.getClass().getName();
+            final int dotPos = name.lastIndexOf('.');
             final String id = node.getId();
             final List<String> selectorStyleClasses = node.getStyleClass();
             simpleSelector = new SimpleSelector(
-                    name,
+                    name.substring(dotPos+1), // want Foo, not bada.bing.Foo
                     selectorStyleClasses,
                     null,
                     id);
@@ -634,7 +564,7 @@
 
                     CascadingStyle s = new CascadingStyle(
                         new Style(Selector.getUniversalSelector(), decl),
-                        null, // no pseudo classes
+                        0, // no pseudo classes
                         0, // specificity is zero
                         // ordinal increments at declaration level since
                         // there may be more than one declaration for the
@@ -685,48 +615,84 @@
     }
 
     /**
-     * dynamic pseudoclass state for this helper - only valid during a pulse 
-     * Set in setPseudoClassStatesForTransition which is called upon entering 
-     * transitionToState. 
+     * 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 example, your stylesheet might have:
+     * <pre><code>
+     * .button { ... }
+     * .button:hover { ... }
+     * .button *.label { text-fill: black }
+     * .button:hover *.label { text-fill: blue }
+     * </code></pre>
+     * In this case, the first 2 rules apply to the Button itself, but the
+     * second two rules apply to the label within a Button. When the hover
+     * changes on the Button, however, we must mark the Button as needing
+     * an UPDATE. StyleHelper though only contains styles for the first two
+     * rules for Button. The pseudoclassStateMask would in this case have
+     * only a single bit set for "hover". In this way the StyleHelper associated
+     * with the Button would know whether a change to "hover" requires the
+     * button and all children to be update. Other pseudoclass state changes
+     * that are not in this hash set are ignored.
      */
-    private long[] pseudoClassStates;
+    private long pseudoclassStateMask;
 
-    // cache pseudoclass state. cleared on each pulse.
-    final static Map<Node,Long> pseudoclassMasksByNode = new HashMap<Node,Long>();
+    /**
+     * dynamic pseudoclass state for this helper - only valid during a pulse. 
+     * Note Well: The array runs from leaf to root. That is, 
+     * transitionStates[0] is the pseudoclassState for node and 
+     * transitionStates[1..(states.length-1)] are the pseudoclassStates for the 
+     * node's parents.
+     */ 
+    private long[] transitionStates;
 
-    // get pseudoclass state for the node (set at StyleHelper creation)
+    
+    // get pseudoclass state for the node 
     long getPseudoClassState() {
-        return pseudoClassStates != null && pseudoClassStates.length > 0 ? pseudoClassStates[0] : 0;
+        // setTransitionState should have been called on this StyleHelper
+        assert (transitionStates != null && transitionStates.length > 0);        
+        return transitionStates != null && transitionStates.length > 0 ? transitionStates[0] : 0;
     }
     
-    private long[] getPseudoClassStates() {
-        return pseudoClassStates;
+    public void setTransitionState(long state) {
+        
+        Parent parent = node.getParent();
+        if (parent != null) {
+            
+            // My transitionStates include those of my parents
+            final StyleHelper helper = parent.impl_getStyleHelper();
+            final long[] parentTransitionStates = helper.getTransitionStates();
+            
+            // setTransitionState should have been called on parent
+            assert (parentTransitionStates != null && parentTransitionStates.length > 0);
+            
+            final int nStates = 
+                (parentTransitionStates != null && parentTransitionStates.length > 0) 
+                    ? parentTransitionStates.length+1 
+                    : 1;
+            
+            if (transitionStates == null || transitionStates.length != nStates) {
+                transitionStates = new long[nStates];
+            }
+            
+            // transtitionStates[0] is my state, so copy parent states to 
+            // transitionStates[1..nStates-1]
+            if (nStates > 1) {
+                // if nStates <= 1, then parentTransitionStates must be null or length zero.
+                System.arraycopy(parentTransitionStates, 0, transitionStates, 1, parentTransitionStates.length);
+            }
+            
+        } else {
+            if (transitionStates == null || transitionStates.length != 1) {
+                transitionStates = new long[1];
+            }            
+        }
+        transitionStates[0] = state;
     }
     
-    /* 
-     * 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.
-     */ 
-    private static long[] getPseudoClassStatesForTransition(Node node, int count) {
-    
-        if (node == null) return new long[count];
-        
-        long[] states = getPseudoClassStatesForTransition(node.getParent(), ++count);
-        
-        StyleHelper helper = node.impl_getStyleHelper();
-        
-        // avoid calling impl_getPseudoClassState if there 
-        // aren't any pseudoclasses that matter
-//        states[count-1] = (helper.pseudoclassStateMask != 0) 
-//                ? node.impl_getPseudoClassState()
-//                : 0;
-        states[count-1] = node.impl_getPseudoClassState();
+    private long[] getTransitionStates() {
+        return transitionStates;
+    }
 
-        return states;
-    }
-    
     /* 
      * The lookup function return an Object but also
      * needs to return whether or not the value is cacheable.
@@ -759,31 +725,22 @@
      * animations and that support is detectable via the API.
      */
     public void transitionToState() {
-
+       
         if (smapRef == null || smapRef.get() == null) return;
 
         //
-        // The ValueCacheEntry to choose depends on this Node's state and
+        // The CacheEntry 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.
         //
-        pseudoClassStates = getPseudoClassStatesForTransition(node, 0);
-
-        // allstates[0] is this node's state
-        long states = pseudoClassStates[0];
-        //
-        // inlineStyles is this node's Node.style. This is passed along and is
-        // used in getStyle. Importance being the same, an author style will
-        // trump a user style and a user style will trump a user_agent style.
-        //
-        final Map<String,CascadingStyle> inlineStyles = this.getInlineStyleMap(node);
-
+        long[] states = getTransitionStates();
+        
         //
         // Styles that need lookup can be cached provided none of the styles
         // are from Node.style.
         //
                 
-        final CacheEntry cacheEntry = getCacheEntry(node, pseudoClassStates);
+        final CacheEntry cacheEntry = getCacheEntry(node, states);
         if (cacheEntry == null 
             || (cacheEntry.sharedCacheRef != null 
                 && cacheEntry.sharedCacheRef.get() == null)) {
@@ -800,6 +757,13 @@
             node.impl_reapplyCSS();
             return;
         }
+
+        //
+        // inlineStyles is this node's Node.style. This is passed along and is
+        // used in getStyle. Importance being the same, an author style will
+        // trump a user style and a user style will trump a user_agent style.
+        //
+        final Map<String,CascadingStyle> inlineStyles = StyleHelper.getInlineStyleMap(node);
         
         //
         // if this node has a style map, then we'll populate it.
@@ -813,7 +777,7 @@
         
         if (cacheEntry.font == null) {
             final CalculatedValue font = 
-                getFontForUseInConvertingRelativeSize(node, cacheEntry, states, inlineStyles);
+                getFontForUseInConvertingRelativeSize(node, cacheEntry, getPseudoClassState(), inlineStyles);
             
             cacheEntry.font = font;
             assert(cacheEntry.font != null);
@@ -895,7 +859,7 @@
 
                 boolean isUserSet = isUserSetProperty(node, styleable);            
 
-                calculatedValue = lookup(node, styleable, isUserSet, states, 
+                calculatedValue = lookup(node, styleable, isUserSet, getPseudoClassState(), 
                         inlineStyles, node, cacheEntry, styleList);
 
                 if (fastpath) {
@@ -905,7 +869,7 @@
                 }
 
             }
-
+            
             // RT-10522:
             // If the user set the property and there is a style and
             // the style came from the user agent stylesheet, then
@@ -995,7 +959,7 @@
         // order finding the first that matches the current node & set of
         // pseudoclass states. We use an iteration style that avoids creating
         // garbage iterators (and wish javac did it for us...)
-        CascadingStyle style = null;
+       CascadingStyle style = null;
         final int max = (styles == null) ? 0 : styles.size();
         for (int i=0; i<max; i++) {
             final CascadingStyle s = styles.get(i);
@@ -1641,7 +1605,7 @@
             parent = parent.getParent();
             if (parent != null) {
                 parentHelper = parent.impl_getStyleHelper();
-                final long[] pstates = parentHelper.getPseudoClassStates();
+                final long[] pstates = parentHelper.getTransitionStates();
                 parentCacheEntry = parentHelper.getCacheEntry(parent, pstates);                
             }
         } while (parent != null && parentCacheEntry == null);
@@ -1903,7 +1867,7 @@
         while (parent != null) {
             
             final long states = helper.getPseudoClassState();
-            final Map<String,CascadingStyle> inlineStyles = helper.getInlineStyleMap(parent);
+            final Map<String,CascadingStyle> inlineStyles = StyleHelper.getInlineStyleMap(parent);
             
             final CascadingStyle cascadingStyle =
                 helper.getStyle(parent, property, states, inlineStyles);
@@ -1949,7 +1913,7 @@
             }
         }
         
-        final long states = pseudoClassStates[0];
+        final long states = getPseudoClassState();
         final Map<String,CascadingStyle> inlineStyles = getInlineStyleMap(node);
 
         String family = null;
@@ -2169,7 +2133,7 @@
                 
                 if (parentHelper != null) {
                     
-                    Map<String,CascadingStyle> inlineStyles = parentHelper.getInlineStyleMap(parent);
+                    Map<String,CascadingStyle> inlineStyles = StyleHelper.getInlineStyleMap(parent);
                     
                     if (inlineStyles != null) {
                         
@@ -2178,12 +2142,12 @@
                         }
                         
                         for(Entry<String,CascadingStyle> entry : inlineStyles.entrySet()) {                            
-                            String key = entry.getKey();
+                            String kee = entry.getKey();
                             
-                            List<CascadingStyle> inlineStyleList = inlineStyleMap.get(key);
+                            List<CascadingStyle> inlineStyleList = inlineStyleMap.get(kee);
                             if (inlineStyleList == null) {
                                 inlineStyleList = new ArrayList<CascadingStyle>();
-                                inlineStyleMap.put(key, inlineStyleList);
+                                inlineStyleMap.put(kee, inlineStyleList);
                             }
                             inlineStyleList.add(entry.getValue());
                         }
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Tue Oct 09 13:07:14 2012 -0700
@@ -778,7 +778,7 @@
     /**
      * Finds matching styles for this Node.
      */
-    StyleMap findMatchingStyles(Node node, SimpleSelector key) {
+    StyleMap findMatchingStyles(Node node, SimpleSelector key, long[] pseudoclassBits) {
         
         //
         // Are there any stylesheets at all?
@@ -812,13 +812,13 @@
             
             final SimpleSelector newKey = new SimpleSelector(key);                    
             cacheMap.put(newKey, cache);
-
+            
         }
 
         //
         // Create a style helper for this node from the styles that match. 
         //
-        StyleMap smap = cache.getStyleMap(this, node);
+        StyleMap smap = cache.getStyleMap(this, node, pseudoclassBits);
         
         return smap;        
     }
@@ -896,7 +896,7 @@
             this.cache = new HashMap<Long, StyleMap>();
         }
 
-        private StyleMap getStyleMap(StyleManager owner, Node node) {
+        private StyleMap getStyleMap(StyleManager owner, Node node, long[] pseudoclassBits) {
             
             if (rules == null || rules.isEmpty()) {                
                 return StyleMap.EMPTY_MAP;
@@ -907,21 +907,11 @@
             // 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.
+            // whittles the list down to those rules that apply.
             //
-            // 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()];
+            final Rule[] applicableRules = new Rule[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 match this particular node are
             // represented by bits on the Long.
@@ -931,46 +921,74 @@
             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) {
+
+                //
+                // This particular flavor of applies takes a long[] and fills 
+                // in the pseudoclass states from the selectors where they apply
+                // to a node. This is an expedient to looking the applies loop
+                // a second time on the matching rules. This has to be done 
+                // ahead of the cache lookup since not all nodes that have the 
+                // same set of rules will have the same node hierarchy. 
+                // 
+                // For example, if I have .foo:hover:focused .bar:selected {...}
+                // and the "bar" node is 4 away from the root and the foo
+                // node is two away from the root, pseudoclassBits would be
+                // [selected, 0, hover:focused, 0]
+                // Note that the states run from leaf to root. This is how
+                // the code in StyleHelper expects things. 
+                // Note also that, if the rule does not apply, the pseudoclassBits
+                // is unchanged. 
+                //
+                if (rule.applies(node, pseudoclassBits)) {
                     
-                    listOfMatches[r] = matches;
+                    applicableRules[r] = rule;
                     key = key | mask;
                     
                 } else {
                     
-                    listOfMatches[r] = null;
+                    applicableRules[r] = null;
                     
                 }
                 mask = mask << 1;
             }
             
             // nothing matched!
-            if (key == 0) return null;
+            if (key == 0) return StyleMap.EMPTY_MAP;
             
             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++) {
+            // if there isn't a map in cache already, create one. 
+            // 
+            // We know the rules apply, so they should also match. A rule
+            // might have more than one selector and match will return the
+            // selector that matches. Matches is more expensive than applies, 
+            // so we pay for it here, but only for the first time the 
+            // cache is created.
+            //
+            final List<CascadingStyle> styles = new ArrayList<CascadingStyle>();
+            
+            for (int r = 0, rMax = applicableRules.length; r<rMax; r++) {
                 
-                final List<Match> matches = listOfMatches[m];
-                if (matches == null) continue; 
+                final Rule rule = applicableRules[r];
                 
-                // the rule that matched
-                Rule rule = rules.get(m);
+                // if the rule didn't apply, then applicableRules[r] will be null
+                if (rule == null) continue;
                 
-                for (int n=0, nMax = matches.size(); n<nMax; n++) {
-                    
-                    final Match match = matches.get(n);
+                final List<Match> matches = rule.matches(node);
+                if (matches == null || matches.isEmpty()) continue;
+                
+                for (int m=0, mMax=matches.size(); m<mMax; m++) {
+                
+                    final Match match = matches.get(m);
                     // 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);
 
--- a/javafx-ui-common/src/javafx/scene/Node.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Tue Oct 09 13:07:14 2012 -0700
@@ -7443,7 +7443,7 @@
         // apply the CSS immediately and not add it to the scene's queue
         // for deferred action.
         if (getParent() != null && getParent().performingLayout) {
-            impl_processCSS(true);
+            impl_processCSS(getScene().styleManager, true);
         } else if (getScene() != null) {
             notifyParentsOfInvalidatedCSS();
         }
@@ -7453,7 +7453,8 @@
         switch (cssFlag) {
             case CLEAN:
                 break;
-            case DIRTY_BRANCH:
+            case DIRTY_BRANCH:     
+                styleHelper.setTransitionState(impl_getPseudoClassState());
                 Parent me = (Parent)this;
                 // clear the flag first in case the flag is set to something
                 // other than clean by downstream processing.
@@ -7479,9 +7480,36 @@
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
     @Deprecated // SB-dependency: RT-21206 has been filed to track this
-    public void impl_processCSS(boolean reapply) {        
-        final StyleManager styleManager = StyleManager.getStyleManager(this.getScene());
-        impl_processCSS(styleManager, reapply);
+    public final void impl_processCSS(boolean reapply) {
+        
+        assert(getScene() != null);
+        if (getScene() == null) return;
+        
+        //
+        // Normally, css is processed from the root down. If this method
+        // is called, then the code is trying to force css to be applied 
+        // in the middle of a pulse.
+        //
+        
+        //
+        // Since StyleHelper expects css to be applied top-down, follow
+        // the path from this node to the root and set the transition states. 
+        // The transitionsStates _have_ to be set from the root on down. 
+        final java.util.Stack<Parent> parents = new java.util.Stack<Parent>();
+        Parent parent = getParent();
+        while (parent != null) {
+            parents.push(parent);
+            parent = parent.getParent();
+        }
+        while (parents.isEmpty() == false) {
+            parent = parents.pop();
+            parent.impl_getStyleHelper().setTransitionState(parent.impl_getPseudoClassState());
+        }
+        
+        final boolean flag = (reapply || cssFlag == CSSFlags.REAPPLY);
+        cssFlag = flag ? CSSFlags.REAPPLY : CSSFlags.UPDATE;
+        final StyleManager styleManager = getScene().styleManager;
+        impl_processCSS(styleManager, flag);
     }
     
     /**
@@ -7493,8 +7521,11 @@
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
     @Deprecated // SB-dependency: RT-21206 has been filed to track this    
-    public void impl_processCSS(StyleManager styleManager, boolean reapply) {
-
+    protected void impl_processCSS(StyleManager styleManager, boolean reapply) {
+        
+        // Nothing to do...
+        if (!reapply && (cssFlag == CSSFlags.CLEAN)) return;
+        
         // 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)) {
@@ -7507,10 +7538,9 @@
         // other than clean by downstream processing.
         cssFlag = CSSFlags.CLEAN;
 
-        // Transition to the new state
-        if (styleHelper != null) {
-            styleHelper.transitionToState();
-        }
+        // Transition to the new state and apply styles
+        styleHelper.setTransitionState(impl_getPseudoClassState());        
+        styleHelper.transitionToState();
     }
     
     /**
--- a/javafx-ui-common/src/javafx/scene/Parent.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Parent.java	Tue Oct 09 13:07:14 2012 -0700
@@ -1078,10 +1078,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();
+                // Notify the StyleManager if stylesheets change. This Parent's
+                // styleManager will get recreated in impl_processCSS.
+                final StyleManager sm = getStyleManager();
                 if (sm != null) sm.stylesheetsChanged(c);
                 
                 // RT-9784 - if stylesheet is removed, reset styled properties to 
@@ -1109,27 +1108,37 @@
     
     private StyleManager styleManager;
     private StyleManager getStyleManager() {
+        return styleManager;
+    }
+    // method should only be called if styles are being reapplied.
+    private StyleManager createStyleManager() {
         
-        final Scene scene = getScene();
+        styleManager = null;
+        
         final boolean hasStylesheets = (getStylesheets().isEmpty() == false);
         
-        if (scene == null) {
+        if (hasStylesheets) {
+
+            // This Parent's styleManager will chain to the styleManager of 
+            // one of its ancestors, or to the scene styleManager.
+            StyleManager parentStyleManager = null;
+            Parent parent = getParent();
+            while (parent != null && 
+                    (parentStyleManager = parent.getStyleManager()) == null) {
+                parent = parent.getParent();
+            }
             
-            styleManager = null;
-            
-        } else if (styleManager == null) {
-            
-            // 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);            
+            if (parentStyleManager != null) {
+                styleManager = 
+                    StyleManager.createStyleManager(Parent.this, parentStyleManager);
+            } else {
+                final Scene scene = getScene();
+                if (scene != null) {
+                    StyleManager.createStyleManager(Parent.this, scene.styleManager);
+                }
             } 
+        
         }
-        
         return styleManager;
     }
     /**
@@ -1174,19 +1183,35 @@
      * @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(StyleManager styleManager, boolean reapply) {
+    @Override protected 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();
+        // Nothing to do...
+        if (!reapply && (cssFlag == CSSFlags.CLEAN)) return;
         
         // Determine whether we will need to reapply from here on down
         boolean flag = reapply || cssFlag == CSSFlags.REAPPLY;
+        
+        // Parent has its own StyleManager which is either adopted from 
+        // Scene or is created new if this Parent has its own stylesheets.
+        // If we're reapplying styles, then re-create this Parent's styleManager, 
+        // which might still be null if there are no stylesheets. 
+        // If we are not reapplying styles, then just get the current styleManager,
+        // which might be null.
+        // If this Parent doesn't have its own StyleManager, then just use
+        // the one passed in.
+        StyleManager sm = flag ? createStyleManager() : getStyleManager();
+        if (sm == null) sm = styleManager;
+
         // Let the super implementation handle CSS for this node
-        super.impl_processCSS(parentStyleManager, flag);
+        super.impl_processCSS(sm, flag);
+        
         // For each child, process CSS
         for (int i=0, max=children.size(); i<max; i++) {
-            children.get(i).impl_processCSS(parentStyleManager, flag);
+            final Node child = children.get(i);
+            // If the parent styles are being updated or reapplied, then
+            // make sure the children are updated or reapplied. 
+            child.cssFlag = (flag ? CSSFlags.REAPPLY : CSSFlags.UPDATE);
+            child.impl_processCSS(sm, flag);
         }
     }
     
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Tue Oct 09 13:07:14 2012 -0700
@@ -77,7 +77,7 @@
             styles.add(
                 new CascadingStyle(
                     new Style(decl.rule.selectors.get(0), decl), 
-                    Collections.EMPTY_LIST,
+                    0,
                     0, 
                     0
                 )
@@ -270,13 +270,7 @@
         final Map<String,List<CascadingStyle>> styleMap = createStyleMap(styles);
         final Map<String,List<CascadingStyle>> emptyMap = createStyleMap(null);
 
-        text = new Text("HelloWorld") {
-            @Override public void impl_processCSS(StyleManager sm, boolean b) {
-                System.err.println("impl_processCSS " + b);
-                super.impl_processCSS(sm,b);
-            }
-        };
-        
+        text = new Text("HelloWorld");
         group.getChildren().add(text);
 
         final List<Declaration> expecteds = new ArrayList<Declaration>();
@@ -296,14 +290,7 @@
                         assertTrue(expecteds.contains(style.getDeclaration()));
                         expecteds.remove(style.getDeclaration());
                     }
-                } else if (change.wasRemoved()) {
-                    List<Style> styles = change.getValueRemoved();
-                    for (Style style : styles) {
-                        System.err.println("removed " + style.toString());
-                    }
-                    
-                }
-                
+                } 
             }
         });
              
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Tue Oct 09 13:07:14 2012 -0700
@@ -151,7 +151,7 @@
         Node node = null;
         Rule instance = null;
         boolean expResult = false;
-        boolean result = instance.applies(node);
+        boolean result = instance.applies(node, null);
         assertEquals(expResult, result);
         fail("The test case is a prototype.");
     }
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/StyleablePropertyTest.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/StyleablePropertyTest.java	Tue Oct 09 13:07:14 2012 -0700
@@ -281,7 +281,7 @@
         }
         return new CascadingStyle(
             new Style(selector, declaration),
-            pseudoclasses,
+            StyleManager.getPseudoclassMask(pseudoclasses),
             0,
             ord++
         );
@@ -752,7 +752,7 @@
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
-        System.err.println("actuals: " + actuals);
+//        System.err.println("actuals: " + actuals);
 
         assertEquals(expecteds.size(), actuals.size(), 0);
         
--- a/javafx-ui-common/test/unit/javafx/scene/CSSNode.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-common/test/unit/javafx/scene/CSSNode.java	Tue Oct 09 13:07:14 2012 -0700
@@ -24,6 +24,7 @@
  */
 package javafx.scene;
 
+import com.sun.javafx.css.StyleManager;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -229,10 +230,10 @@
     public boolean applyCalled = false;
 
     @Override
-    public void impl_processCSS(boolean reapply) {
+    protected void impl_processCSS(StyleManager mgr, boolean reapply) {
         this.reapply = reapply;
         processCalled = true;
-        super.impl_processCSS(reapply);
+        super.impl_processCSS(mgr, reapply);
     }
 
     @Override
--- a/javafx-ui-common/test/unit/javafx/scene/layout/BorderImageSlicesTest.java	Tue Oct 09 09:42:23 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 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 javafx.scene.layout;
-
-import org.junit.Test;
-
-/**
- */
-public class BorderImageSlicesTest {
-    @Test public void instanceCreation() {
-//        BorderImageSlices slices = new BorderImageSlices(.1, .2, .3, .4, false, true, false, true, false);
-//        assertEquals(.1, slices.getTop(), 0);
-//        assertEquals(.2, slices.getRight(), 0);
-//        assertEquals(.3, slices.getBottom(), 0);
-//        assertEquals(.4, slices.getLeft(), 0);
-//        assertFalse(slices.isTopAsPercentage());
-//        assertTrue(slices.isRightAsPercentage());
-//        assertFalse(slices.isBottomAsPercentage());
-//        assertTrue(slices.isLeftAsPercentage());
-//        assertFalse(slices.isFilled());
-    }
-//
-//    @Test public void instanceCreation2() {
-//        BorderImageSlices slices = new BorderImageSlices(.1, .2, .3, .4, true, false, true, false, true);
-//        assertEquals(.1, slices.getTop(), 0);
-//        assertEquals(.2, slices.getRight(), 0);
-//        assertEquals(.3, slices.getBottom(), 0);
-//        assertEquals(.4, slices.getLeft(), 0);
-//        assertTrue(slices.isTopAsPercentage());
-//        assertFalse(slices.isRightAsPercentage());
-//        assertTrue(slices.isBottomAsPercentage());
-//        assertFalse(slices.isLeftAsPercentage());
-//        assertTrue(slices.isFilled());
-//    }
-//
-//    @Test public void instanceCreation3() {
-//        BorderImageSlices slices = new BorderImageSlices(.1, .2, .3, .4, true, false, false, true, false);
-//        assertEquals(.1, slices.getTop(), 0);
-//        assertEquals(.2, slices.getRight(), 0);
-//        assertEquals(.3, slices.getBottom(), 0);
-//        assertEquals(.4, slices.getLeft(), 0);
-//        assertTrue(slices.isTopAsPercentage());
-//        assertFalse(slices.isRightAsPercentage());
-//        assertFalse(slices.isBottomAsPercentage());
-//        assertTrue(slices.isLeftAsPercentage());
-//    }
-//
-//    @Test public void topPercentGreaterThanOneShouldBeClampedToOne() {
-//        BorderImageSlices slices = new BorderImageSlices(2, 0, 0, 0, true, false, false, false, false);
-//        assertEquals(1, slices.getTop(), 0);
-//    }
-//
-//    @Test public void rightPercentGreaterThanOneShouldBeClampedToOne() {
-//        BorderImageSlices slices = new BorderImageSlices(0, 2, 0, 0, false, true, false, false, false);
-//        assertEquals(1, slices.getRight(), 0);
-//    }
-//
-//    @Test public void bottomPercentGreaterThanOneShouldBeClampedToOne() {
-//        BorderImageSlices slices = new BorderImageSlices(0, 0, 2, 0, false, false, true, false, false);
-//        assertEquals(1, slices.getBottom(), 0);
-//    }
-//
-//    @Test public void leftPercentGreaterThanOneShouldBeClampedToOne() {
-//        BorderImageSlices slices = new BorderImageSlices(0, 0, 0, 2, false, false, false, true, false);
-//        assertEquals(1, slices.getLeft(), 0);
-//    }
-//
-//    @Test(expected = IllegalArgumentException.class)
-//    public void cannotSpecifyNegativeTop() {
-//        new BorderImageSlices(-2, 0, 0, 0, false, false, false, false, false);
-//    }
-//
-//    @Test(expected = IllegalArgumentException.class)
-//    public void cannotSpecifyNegativeRight() {
-//        new BorderImageSlices(0, -2, 0, 0, false, false, false, false, false);
-//    }
-//
-//    @Test(expected = IllegalArgumentException.class)
-//    public void cannotSpecifyNegativeBottom() {
-//        new BorderImageSlices(0, 0, -2, 0, false, false, false, false, false);
-//    }
-//
-//    @Test(expected = IllegalArgumentException.class)
-//    public void cannotSpecifyNegativeLeft() {
-//        new BorderImageSlices(0, 0, 0, -2, false, false, false, false, false);
-//    }
-//
-//    @Test public void equality() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        assertEquals(a, b);
-//    }
-//
-//    @Test public void same() {
-//        assertEquals(BorderImageSlices.EMPTY, BorderImageSlices.EMPTY);
-//    }
-//
-//    @Test public void different() {
-//        BorderImageSlices a = new BorderImageSlices(.5, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(.6, 2, 3, 4, true, false, false, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different2() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 3, 3, 4, true, false, false, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different3() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 4, 4, true, false, false, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different4() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, .4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 3, .5, true, false, false, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different5() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 3, 4, false, false, false, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different6() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 3, 4, true, true, false, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different7() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 3, 4, true, false, true, true, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void different8() {
-//        BorderImageSlices a = new BorderImageSlices(1, 2, 3, 4, true, false, false, true, false);
-//        BorderImageSlices b = new BorderImageSlices(1, 2, 3, 4, true, false, false, false, false);
-//        assertFalse(a.equals(b));
-//    }
-//
-//    @Test public void noEqualToNull() {
-//        assertFalse(BorderImageSlices.EMPTY.equals(null));
-//    }
-//
-//    @Test public void noEqualToRandom() {
-//        assertFalse(BorderImageSlices.EMPTY.equals("Some random value"));
-//    }
-}
--- a/javafx-ui-common/test/unit/javafx/scene/layout/BorderImageSlices_builder_Test.java	Tue Oct 09 09:42:23 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 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 javafx.scene.layout;
-
-import org.junit.Test;
-
-/**
- */
-//@RunWith(Parameterized.class)
-public class BorderImageSlices_builder_Test { //extends BuilderTestBase {
-    @Test public void dummy() { }
-//    @Parameterized.Parameters
-//    public static Collection data() {
-//        BuilderTestBase.Configuration cfg = new BuilderTestBase.Configuration(BorderImageSlices.class);
-//        cfg.addProperty("top", 1.0);
-//        cfg.addProperty("right", 2.0);
-//        cfg.addProperty("bottom", 3.0);
-//        cfg.addProperty("left", .4);
-//        cfg.addProperty("topAsPercentage", true);
-//        cfg.addProperty("rightAsPercentage", false);
-//        cfg.addProperty("bottomAsPercentage", false);
-//        cfg.addProperty("leftAsPercentage", true);
-//        cfg.addProperty("filled", true);
-//
-//        BuilderTestBase.Configuration cfg2 = new BuilderTestBase.Configuration(BorderImageSlices.class);
-//        cfg2.addProperty("topAsPercentage", false);
-//        cfg2.addProperty("rightAsPercentage", true);
-//        cfg2.addProperty("bottomAsPercentage", true);
-//        cfg2.addProperty("leftAsPercentage", false);
-//
-//        BuilderTestBase.Configuration cfg3 = new BuilderTestBase.Configuration(BorderImageSlices.class);
-//        cfg3.addProperty("topAsPercentage", false);
-//        cfg3.addProperty("rightAsPercentage", true);
-//        cfg3.addProperty("bottomAsPercentage", false);
-//        cfg3.addProperty("leftAsPercentage", true);
-//
-//        return Arrays.asList(
-//                new Object[] {
-//                        config(cfg),
-//                        config(cfg2),
-//                        config(cfg3)
-//                });
-//    }
-//
-//    public BorderImageSlices_builder_Test(final Configuration configuration) {
-//        super(configuration);
-//    }
-}
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Tue Oct 09 13:07:14 2012 -0700
@@ -118,7 +118,8 @@
 
         @Override protected void invalidated() {
             if (getWidth() > 0) {
-                textNode.impl_caretBiasProperty().set(get());
+                // RT-25479: Disable caret bias handling for now.
+                // textNode.impl_caretBiasProperty().set(get());
                 updateCaretOff();
             }
         }
@@ -383,7 +384,6 @@
                     Point2D p = new Point2D(caretHandle.getLayoutX() + e.getX() + pressX - textNode.getLayoutX(),
                                             caretHandle.getLayoutY() + e.getY() - pressY - 6);
                     HitInfo hit = textNode.impl_hitTestChar(translateCaretPosition(p));
-                    int pos = hit.getCharIndex();
                     positionCaret(hit, false);
                     e.consume();
                 }
@@ -674,7 +674,8 @@
     }
 
     public void positionCaret(HitInfo hit, boolean select) {
-        int pos = hit.getCharIndex();
+//         int pos = hit.getCharIndex();
+        int pos = hit.getInsertionIndex();
         boolean isNewLine =
                (pos > 0 &&
                 pos < getSkinnable().getLength() &&
--- a/javafx-ui-controls/src/javafx/scene/control/Control.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/control/Control.java	Tue Oct 09 13:07:14 2012 -0700
@@ -741,7 +741,7 @@
      * @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(StyleManager styleManager, boolean reapply) {
+    @Override protected void impl_processCSS(StyleManager styleManager, boolean reapply) {
         if (reapply && getUserAgentStylesheet() != null) {
             styleManager.addUserAgentStylesheet(getUserAgentStylesheet());
         }
--- a/javafx-ui-controls/src/javafx/scene/control/MultipleSelectionModelBase.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/control/MultipleSelectionModelBase.java	Tue Oct 09 13:07:14 2012 -0700
@@ -229,6 +229,7 @@
         if (shift > 0) {
             for (int i = selectedIndicesSize - 1; i >= position && i >= 0; i--) {
                 boolean selected = selectedIndices.get(i);
+                selectedIndices.clear(i);
                 selectedIndices.set(i + shift, selected);
 
                 if (selected) {
@@ -240,6 +241,7 @@
             for (int i = position; i < selectedIndicesSize; i++) {
                 if ((i + shift) < 0) continue;
                 boolean selected = selectedIndices.get(i + 1);
+                selectedIndices.clear(i + 1);
                 selectedIndices.set(i + 1 + shift, selected);
 
                 if (selected) {
@@ -251,6 +253,7 @@
         // This ensure that the selection remains accurate when a shift occurs.
         if (getFocusedIndex() >= position && getFocusedIndex() > -1 && getFocusedIndex() + shift > -1) {
             setSelectedIndex(getFocusedIndex() + shift);
+            focus(getFocusedIndex() + shift);
         }
          
         selectedIndicesSeq.callObservers(
--- a/javafx-ui-controls/test/javafx/scene/control/PopupControlTest.java	Tue Oct 09 09:42:23 2012 -0700
+++ b/javafx-ui-controls/test/javafx/scene/control/PopupControlTest.java	Tue Oct 09 13:07:14 2012 -0700
@@ -24,6 +24,10 @@
 
     @Before public void setup() {
         popup = new PopupControl();
+        // PopupControl normally gets its stylesheet from the owner scene.
+        popup.getScene().getStylesheets().add(
+            PopupControlSkin.class.getResource("caspian/caspian.css").toExternalForm()
+        );
     }
 
     /*********************************************************************