changeset 2673:feb390345e62

RT-26614: move StyleHelper to javafx.scene as CssStyleHelper
author David Grieve<david.grieve@oracle.com>
date Fri, 22 Feb 2013 15:41:59 -0500
parents fdec9eafd1ca
children e652ee669c85
files javafx-ui-common/src/com/sun/javafx/css/BitSet.java javafx-ui-common/src/com/sun/javafx/css/CalculatedValue.java javafx-ui-common/src/com/sun/javafx/css/CascadingStyle.java javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java javafx-ui-common/src/com/sun/javafx/css/Match.java javafx-ui-common/src/com/sun/javafx/css/ParsedValueImpl.java javafx-ui-common/src/com/sun/javafx/css/PseudoClassImpl.java javafx-ui-common/src/com/sun/javafx/css/PseudoClassSet.java javafx-ui-common/src/com/sun/javafx/css/PseudoClassState.java javafx-ui-common/src/com/sun/javafx/css/Rule.java javafx-ui-common/src/com/sun/javafx/css/Selector.java javafx-ui-common/src/com/sun/javafx/css/SelectorPartitioning.java javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java javafx-ui-common/src/com/sun/javafx/css/StyleCache.java javafx-ui-common/src/com/sun/javafx/css/StyleCacheEntry.java javafx-ui-common/src/com/sun/javafx/css/StyleClass.java javafx-ui-common/src/com/sun/javafx/css/StyleClassSet.java javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java javafx-ui-common/src/com/sun/javafx/css/StyleManager.java javafx-ui-common/src/com/sun/javafx/css/StyleMap.java javafx-ui-common/src/javafx/css/PseudoClass.java javafx-ui-common/src/javafx/scene/CssStyleHelper.java javafx-ui-common/src/javafx/scene/Node.java javafx-ui-common/test/unit/com/sun/javafx/css/CssMetaDataTest.java javafx-ui-common/test/unit/com/sun/javafx/css/HonorDeveloperSettingsTest.java javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java javafx-ui-common/test/unit/com/sun/javafx/css/PseudoClassTest.java javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java javafx-ui-common/test/unit/com/sun/javafx/css/SelectorPartitioningTest.java
diffstat 29 files changed, 3734 insertions(+), 3685 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/css/BitSet.java	Fri Feb 22 15:41:59 2013 -0500
@@ -0,0 +1,454 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * Pseudo-class state and style-classes are represented as bits in a long[]
+ * which makes matching faster.
+ */
+abstract class BitSet<T>  implements Set<T> {
+
+    /** Create an empty set of T */
+    protected BitSet () {
+        this.bits = EMPTY_SET;
+    }
+
+    
+    /** {@inheritDoc} */
+    @Override
+    public int size() {
+
+        int size = 0;
+        if (bits.length > 0) {
+            for (int n = 0; n < bits.length; n++) {
+                final long mask = bits[n];
+                if (mask != 0) {
+                    size += Long.bitCount(mask);
+                }
+            }
+        }
+        // index.length is zero or all index[n] values are zero
+        return size;
+
+    }
+
+    @Override
+    public boolean isEmpty() {
+        
+        if (bits.length > 0) {
+            for (int n = 0; n < bits.length; n++) {
+                final long mask = bits[n];
+                if (mask != 0) {
+                    return false;
+                }
+            }
+        }
+        // index.length is zero or all index[n] values are zero
+        return true;
+
+    }
+
+    /**
+     * {@inheritDoc} This returned iterator is not fail-fast.
+     */
+    @Override
+    public Iterator<T> iterator() {
+        
+        return new Iterator<T>() {
+            int next = -1;
+            int element = 0;
+            int index = -1;
+            
+            @Override
+            public boolean hasNext() {
+                if (bits == null || bits.length == 0) {
+                    return false;
+                }
+
+                boolean found = false;
+                
+                do {
+                    if (++next >= Long.SIZE) {
+                        if (++element < bits.length) {
+                            next = 0;
+                        } else {
+                            return false;
+                        }
+                    }                        
+                    
+                    long bit = 1l << next;
+                    found = (bit & bits[element]) == bit;
+                    
+                } while( !found );
+                
+                if (found) {
+                    index = Long.SIZE * element + next;
+                }
+                return found;
+            }
+
+            @Override
+            public T next() {
+                try {
+                    return getT(index);
+                } catch (IndexOutOfBoundsException e) {
+                    throw new NoSuchElementException("["+element+"]["+next+"]");
+                }
+            }
+
+            @Override
+            public void remove() {
+                try {
+                    T t = getT(index);
+                    BitSet.this.remove(t);
+                } catch (IndexOutOfBoundsException e) {
+                    throw new NoSuchElementException("["+element+"]["+next+"]");
+                }
+            }
+        };
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean add(T t) {
+        
+        if (t == null) {
+            // this not modified!
+            return false;
+        }
+        
+        final int element = getIndex(t) / Long.SIZE;
+        final long bit = 1l << (getIndex(t) % Long.SIZE);
+        
+        // need to grow?
+        if (element >= bits.length) {
+            final long[] temp = new long[element + 1];
+            System.arraycopy(bits, 0, temp, 0, bits.length);
+            bits = temp;
+        }
+        
+        final long temp = bits[element];
+        bits[element] = temp | bit;
+        
+        // if index[element] == temp, then the bit was already set
+        final boolean modified = (bits[element] != temp);
+        return modified;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean remove(Object o) {
+        
+        if (o == null) {
+            // this not modified!
+            return false;
+        }
+
+        T t = cast(o);
+
+        final int element = getIndex(t) / Long.SIZE;
+        final long bit = 1l << (getIndex(t) % Long.SIZE);
+
+        if (element >= bits.length) {
+            // not in this Set!
+            return false;
+        }
+        
+        final long temp = bits[element];
+        bits[element] = temp & ~bit;
+
+        // if index[element] == temp, then the bit was not there
+        final boolean modified = (bits[element] != temp);
+        return modified;
+    }
+
+    
+    /** {@inheritDoc} */
+    @Override
+    public boolean contains(Object o) {
+        if (o == null) {
+            return false;
+        }
+        
+        final T t = cast(o);
+
+        final int element = getIndex(t) / Long.SIZE;
+        final long bit = 1l << (getIndex(t) % Long.SIZE);
+
+        return (element < bits.length) && (bits[element] & bit) == bit;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public boolean containsAll(Collection<?> c) {
+
+        if (c == null) {
+            // this not modified!
+            return false;
+        }
+        
+        if (c instanceof BitSet) {
+            
+            BitSet other = (BitSet)c;
+            
+            // this contains all of other if both are empty
+            if (bits.length == 0 && other.bits.length == 0) {
+                return true;
+            }
+            // [foo] cannot contain all of [foo bar]
+            if (bits.length < other.bits.length) {
+                return false;
+            }
+            // does [foo bar bang] contain all 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;
+        }
+        
+        // [foo] cannot contain all of [foo bar]
+        if (size() < c.size()) {
+            return false;
+        }
+
+        // The hard way...        
+        for (Iterator<?> iter = c.iterator(); iter.hasNext();) {
+            final T bitSet = (T) iter.next();
+            if (!contains(bitSet)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean addAll(Collection<? extends T> c) {
+        
+        if (c == null) {
+            // this not modified!
+            return false;
+        }
+        
+        boolean modified = false;
+        
+        if (c instanceof BitSet) {
+            
+            BitSet other = (BitSet)c;
+            
+            if (other.isEmpty()) {
+                // this not modified!
+                return false;
+            } 
+            
+            final long[] maskOne = this.bits;
+            final long[] maskTwo = other.bits;
+
+            final int max = Math.max(maskOne.length, maskTwo.length);
+            final long[] union = new long[max];
+            
+            for(int n = 0; n < max; n++) {
+                
+                if (n < maskOne.length && n < maskTwo.length) {
+                    union[n] = maskOne[n] | maskTwo[n];
+                    modified |= (union[n] != maskOne[n]);
+                } else if (n < maskOne.length) {
+                    union[n] = maskOne[n];
+                    modified |= false;
+                } else {
+                    union[n] = maskTwo[n];
+                    modified = true;
+                }
+                
+            }
+            if (modified) {
+                this.bits = union;
+            }
+            return modified;
+        }
+        
+        // The hard way...
+        for (Iterator<?> iter = c.iterator(); iter.hasNext();) {
+            final T bitSet = (T) iter.next();
+            modified |= add(bitSet);
+        }
+        return modified;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean retainAll(Collection<?> c) {
+
+        if (c == null) {
+            // this not modified!
+            return false;
+        }
+        
+        boolean modified = false;
+        if (c instanceof BitSet) {
+            
+            BitSet other = (BitSet)c;
+            
+            if (other.isEmpty()) {
+                // this not modified!
+                return false;
+            }
+
+            final long[] maskOne = this.bits;
+            final long[] maskTwo = other.bits;
+
+            final int max = Math.min(maskOne.length, maskTwo.length);
+            for(int n = 0; n < max; n++) {
+                long temp = maskOne[n] & maskTwo[n];
+                
+                modified |= temp != maskOne[n];
+                
+                maskOne[n] = temp; 
+            }
+            
+            return modified;
+        }
+        
+        for (Iterator<?> iter = iterator(); iter.hasNext();) {
+            final T bitSet = (T) iter.next();
+            if (!c.contains(bitSet)) {
+                modified |= remove(bitSet);
+            }
+        }
+        return modified;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        
+        if (c == null) {
+            // this not modified!
+            return false;
+        }
+        
+        boolean modified = false;
+        
+        if (c instanceof BitSet) {
+            
+            BitSet other = (BitSet)c;
+            
+            if (other.isEmpty()) {
+                // this was not modified!
+                return false;
+            }
+
+            final long[] maskOne = bits;
+            final long[] maskTwo = other.bits;
+
+            final int max = Math.min(maskOne.length, maskTwo.length);
+            for(int n = 0; n < max; n++) {
+                long temp = maskOne[n] & ~maskTwo[n];
+
+                modified |= temp != maskOne[n];
+                
+                maskOne[n] = temp;
+            }
+
+            return modified;            
+        }
+        
+        // the hard way...
+        if (size() <= c.size()) {
+            for (Iterator<?> iter = c.iterator(); iter.hasNext();) {
+                final BitSet bitSet = (BitSet) iter.next();
+                if (contains(bitSet)) {
+                    modified |= remove(bitSet);
+                }
+            }
+        } else {
+            for (Iterator<T> iter = iterator(); iter.hasNext();) {
+                final BitSet bitSet = (BitSet) iter.next();
+                if (c.contains(bitSet)) {
+                    modified |= remove(bitSet);
+                }
+            }
+        }
+        return modified;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void clear() {
+        bits = new long[1];
+    }
+    
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 71 * hash + Arrays.hashCode(this.bits);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final BitSet other = (BitSet) obj;
+        if (!Arrays.equals(this.bits, other.bits)) {
+            return false;
+        }
+        return true;
+    }
+
+    abstract protected T getT(int index);
+    abstract protected int getIndex(T t);
+    
+    /*
+     * Try to cast the arg to a T.
+     * @throws ClassCastException if the class of the argument is
+     *         is not a T
+     * @throws NullPointerException if the argument is null
+     */
+    abstract protected T cast(Object o);
+    
+    protected long[] getBits() {
+        return bits;
+    }
+    
+    private static long[] EMPTY_SET = new long[0];
+
+    // the set
+    private long[] bits;
+
+}
+
--- a/javafx-ui-common/src/com/sun/javafx/css/CalculatedValue.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/CalculatedValue.java	Fri Feb 22 15:41:59 2013 -0500
@@ -26,11 +26,11 @@
 
 import javafx.css.StyleOrigin;
 
-class CalculatedValue {
+public final class CalculatedValue {
 
-    static final CalculatedValue SKIP = new CalculatedValue(new int[0], null, false);
+    public static final CalculatedValue SKIP = new CalculatedValue(new int[0], null, false);
 
-    CalculatedValue(Object value, StyleOrigin origin, boolean relative) {
+    public CalculatedValue(Object value, StyleOrigin origin, boolean relative) {
             
         this.value = value;            
         this.origin = origin;
--- a/javafx-ui-common/src/com/sun/javafx/css/CascadingStyle.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/CascadingStyle.java	Fri Feb 22 15:41:59 2013 -0500
@@ -28,20 +28,21 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
+import javafx.css.PseudoClass;
 import javafx.css.StyleOrigin;
 
 
 /** A marriage of pseudo-classes (potentially empty) to property and value */
-class CascadingStyle implements Comparable<CascadingStyle> {
+public class CascadingStyle implements Comparable<CascadingStyle> {
 
     /** */
     private final Style style;
-    Style getStyle() {
+    public Style getStyle() {
         return style;
     }
     
     /** State variables, like &quot;hover&quot; or &quot;pressed&quot; */
-    private long[] pseudoClasses;
+    private Set<PseudoClass> pseudoClasses;
 
     /* specificity of the rule that matched */
     private final int specificity;
@@ -58,7 +59,7 @@
     // internal to Style
     static private Set<String> strSet = new HashSet<String>();
 
-    CascadingStyle(final Style style, long[] pseudoClasses, 
+    public CascadingStyle(final Style style, Set<PseudoClass> pseudoClasses, 
             final int specificity, final int ordinal) {
         this.style = style;
         this.pseudoClasses = pseudoClasses;
@@ -68,33 +69,33 @@
     }
         
     // Wrapper to make StyleHelper's life a little easier
-    String getProperty() {
+    public String getProperty() {
         return style.getDeclaration().getProperty();
     }
     
     // Wrapper to make StyleHelper's life a little easier
-    Selector getSelector() {
+    public Selector getSelector() {
         return style.getSelector();
     }
     
     // Wrapper to make StyleHelper's life a little easier
-    Rule getRule() {
+    public Rule getRule() {
         return style.getDeclaration().getRule();
     }
     
     // Wrapper to make StyleHelper's life a little easier
-    StyleOrigin getOrigin() {
+    public StyleOrigin getOrigin() {
         return getRule().getOrigin();
     }
     
     // Wrapper to make StyleHelper's life a little easier
-    ParsedValueImpl getParsedValueImpl() {
+    public ParsedValueImpl getParsedValueImpl() {
         return style.getDeclaration().getParsedValueImpl();
     }
     
     /**
      * When testing equality against another Style, we only care about
-     * the property and pseudoclasses. In other words, we only care about
+     * the property and pseudo-classes. In other words, we only care about
      * where the style is applied, not what is applied.
      */
     @Override public boolean equals(Object obj) {
@@ -113,7 +114,11 @@
         }
         
         // does [foo bar bang] contain all of [foo bar]?
-        return Arrays.equals(pseudoClasses, other.pseudoClasses);
+        if (pseudoClasses == null ? other.pseudoClasses != null : !pseudoClasses.containsAll(other.pseudoClasses)) {
+            return false;            
+        }
+        
+        return true;
 
     }
 
--- a/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Fri Feb 22 15:41:59 2013 -0500
@@ -31,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import javafx.css.PseudoClass;
 
 import javafx.scene.Node;
@@ -122,17 +123,9 @@
             final Match ancestorMatch = matches(parent, index-1);
             if (ancestorMatch != null) {
 
-                final int nPseudoClasses = 
-                    Math.max(ancestorMatch.pseudoClasses.length, descendantMatch.pseudoClasses.length);
-                long[] allPseudoClasses = new long[nPseudoClasses];
-                
-                for (int n=0; n<ancestorMatch.pseudoClasses.length; n++) {
-                    allPseudoClasses[n] = ancestorMatch.pseudoClasses[n];
-                }
-                
-                for (int n=0; n<descendantMatch.pseudoClasses.length; n++) {
-                    allPseudoClasses[n] |= descendantMatch.pseudoClasses[n];
-                }
+                final PseudoClassState allPseudoClasses = new PseudoClassState();
+                allPseudoClasses.addAll(ancestorMatch.pseudoClasses);
+                allPseudoClasses.addAll(descendantMatch.pseudoClasses);
                 
                 return new Match(this, 
                         allPseudoClasses,
@@ -148,63 +141,57 @@
     }
 
     @Override
-    Match matches(final Scene scene) {
-        // TBD: do compound selectors make sense for Scene?
-        return null;
-    }
-
-    @Override
     public boolean applies(final Node node) {
         return applies(node, selectors.size()-1, null, 0);
     }
 
     @Override
-    boolean applies(final Node node, long[][] pseudoClassBits, int depth) {
+    boolean applies(final Node node, Set<PseudoClass>[] triggerStates, int depth) {
         
-        assert (pseudoClassBits == null || depth < pseudoClassBits.length);        
-        if (pseudoClassBits != null && pseudoClassBits.length <= depth) {
+        assert (triggerStates == null || depth < triggerStates.length);        
+        if (triggerStates != null && triggerStates.length <= depth) {
             return false;
         }
         
         // 
-        // We only care about pseudoclassBits if the selector applies. But in
+        // We only care about pseudo-class 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
+        // the setting of pseudo-class has to be deferred until we know
         // that this compound selector applies. So we'll send a new 
-        // long[] and if the compound selector applies, just copy the bits back. 
+        // PseudoClassSet[] and if the compound selector applies, 
+        // just copy the state back. 
         //
-        final long[][] tempBits = pseudoClassBits != null 
-                ? new long[pseudoClassBits.length][0] : null;
-        final boolean applies = applies(node, selectors.size()-1, tempBits, depth);
+        final Set<PseudoClass>[] tempStates = triggerStates != null 
+                ? new PseudoClassState[triggerStates.length] : null;
         
-        if (applies && tempBits != null) {
+        final boolean applies = applies(node, selectors.size()-1, tempStates, depth);
+        
+        if (applies && tempStates != null) {
             
-            for(int n=0; n<pseudoClassBits.length; n++) {
-                long[] bitsOut = pseudoClassBits[n];
-                long[] bitsIn = tempBits[n];
-                if (bitsOut == null || bitsOut.length < bitsIn.length) {
-                    long[] temp = new long[bitsIn.length];
-                    if (bitsOut != null) {
-                        System.arraycopy(bitsOut, 0, temp, 0, bitsOut.length);
-                    }
-                    bitsOut = pseudoClassBits[n] = temp;
-                }
-                for (int b=0; b<bitsIn.length; b++) {
-                    bitsOut[b] |= bitsIn[b];
-                }
+            for(int n=0; n<triggerStates.length; n++) {
+                                
+                final Set<PseudoClass> pseudoClassOut = triggerStates[n];
+                final Set<PseudoClass> pseudoClassIn = tempStates[n];
+                
+                if (pseudoClassOut != null) {
+                    pseudoClassOut.addAll(pseudoClassIn);
+                } else {
+                    triggerStates[n] = pseudoClassIn;
+                } 
+            
             }
         }
         return applies;
     }
 
-    private boolean applies(final Node node, final int index, long[][] pseudoclassBits, int depth) {
+    private boolean applies(final Node node, final int index, Set<PseudoClass>[] triggerStates, int depth) {
         // 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, pseudoclassBits, depth)) return false;
+        if (! selectors.get(index).applies(node, triggerStates, depth)) return false;
 
         // If there are no more selectors to check (ie: index == 0) then we
         // know we know we apply
@@ -224,11 +211,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, pseudoclassBits, ++depth);
+            return applies(parent, index - 1, triggerStates, ++depth);
         } else {
              Node parent = node.getParent();
             while (parent != null) {
-                boolean answer = applies(parent, index - 1, pseudoclassBits, ++depth);
+                boolean answer = applies(parent, index - 1, triggerStates, ++depth);
                 // If a call to stateMatches succeeded, then we know that
                 // all preceding selectors will have also matched.
                 if (answer) return true;
@@ -240,11 +227,11 @@
     }
 
     @Override
-    boolean stateMatches(final Node node, long[] states) {
+    public boolean stateMatches(final Node node, Set<PseudoClass> states) {
         return stateMatches(node, states, selectors.size()-1);
     }
 
-    private boolean stateMatches(Node node, long[] states, int index) {
+    private boolean stateMatches(Node node, Set<PseudoClass> states, int index) {
         // If the index is < 0 then we know we don't match
         if (index < 0) return false;
 
@@ -269,9 +256,8 @@
             final Node parent = node.getParent();
             if (parent == null) return false;
             if (selectors.get(index-1).applies(parent)) {
-                final StyleHelper parentStyleHelper = parent.impl_getStyleHelper();
-                if (parentStyleHelper == null) return false;
-                long[] parentStates = parentStyleHelper.getPseudoClassBits();
+                PseudoClassState parentStates = new PseudoClassState();
+                parentStates.addAll(parent.getPseudoClassStates());
                 // If this call succeeds, then all preceding selectors will have
                 // matched due to the recursive nature of the call
                 return stateMatches(parent, parentStates, index - 1);
@@ -280,18 +266,9 @@
             Node parent = node.getParent();
             while (parent != null) {
                 if (selectors.get(index-1).applies(parent)) { 
-                    final StyleHelper parentStyleHelper = parent.impl_getStyleHelper();
-                    if (parentStyleHelper != null) {
-                        long[] parentStates = parentStyleHelper.getPseudoClassBits();
-                        return stateMatches(parent, parentStates, index - 1);
-                    } else {
-                        // What does it mean for a parent to have a null StyleHelper? 
-                        // In node, StyleHelper is held as a Reference, so if
-                        // the Node's StyleHelper is GC'd, impl_getStyleHelper()
-                        // is going to return null. This can happen if the 
-                        // StyleManager's StyleHelper cache is cleared. 
-                        return false;
-                    }
+                    PseudoClassState parentStates = new PseudoClassState();
+                    parentStates.addAll(parent.getPseudoClassStates());
+                    return stateMatches(parent, parentStates, index - 1);
                 }
                 // Otherwise we need to get the next parent and try again
                 parent = parent.getParent();
--- a/javafx-ui-common/src/com/sun/javafx/css/Match.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/Match.java	Fri Feb 22 15:41:59 2013 -0500
@@ -36,10 +36,10 @@
 /**
  * Returned by {@link Selector#matches} in the event of a match.
  */
-final class Match implements Comparable {
+final class Match implements Comparable<Match> {
 
     final Selector selector;
-    final long[] pseudoClasses;
+    final PseudoClassState pseudoClasses;
     final int idCount;
     final int styleClassCount;
     
@@ -49,18 +49,14 @@
     // then pseudoclass count, and finally matching types (i.e., java name count)
     final int specificity;
 
-    Match(final Selector selector, long[] pseudoClasses,
+    Match(final Selector selector, PseudoClassState pseudoClasses,
             int idCount, int styleClassCount) {
         assert selector != null;
         this.selector = selector;
         this.idCount = idCount;
         this.styleClassCount = styleClassCount;
         this.pseudoClasses = pseudoClasses;
-        int nPseudoClasses = 0;
-        int nMax = pseudoClasses != null ? pseudoClasses.length : 0;
-        for (int n = 0; n < nMax; n++) {
-            nPseudoClasses += Long.bitCount(pseudoClasses[n]);
-        }
+        int nPseudoClasses = pseudoClasses != null ? pseudoClasses.size() : 0;
         if (selector instanceof SimpleSelector) {
             final SimpleSelector simple = (SimpleSelector)selector;
             if (simple.getNodeOrientation() != INHERIT) {
@@ -71,26 +67,8 @@
     }
         
     @Override
-    public int compareTo(Object o) {
-        Match m = (Match)o;
-        return specificity - m.specificity;
+    public int compareTo(Match o) {
+        return specificity - o.specificity;
     }
 
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(selector);
-        for(PseudoClass s : PseudoClassSet.getPseudoClasses(pseudoClasses)) {
-            sb.append(":");
-            sb.append(s.getPseudoClassName());
-        }
-        sb.append(", ");
-        sb.append(idCount);
-        sb.append(", ");
-        sb.append(styleClassCount);
-        sb.append(", 0x");
-        sb.append(Integer.toHexString(specificity));
-
-        return sb.toString();
-    }
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/ParsedValueImpl.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/ParsedValueImpl.java	Fri Feb 22 15:41:59 2013 -0500
@@ -196,13 +196,22 @@
      * nulled out after this ParsedValueImpl object has been converted in the 
      * StyleHelper.lookup method. 
      */
-    ParsedValueImpl resolved;
+    private ParsedValueImpl resolved;
+
+    public ParsedValueImpl getResolved() {
+        return resolved;
+    }
+
+    public void setResolved(ParsedValueImpl resolved) {
+        if (resolved == null) nullResolved();
+        this.resolved = resolved;
+    }
 
     /*
      * Null out the resolved field after this ParsedValueImpl object has been converted.
      * Called from StyleHelper.lookup.
      */
-    void nullResolved() {
+    private void nullResolved() {
 
         if (resolved == this || resolved == null) return;
 
--- a/javafx-ui-common/src/com/sun/javafx/css/PseudoClassImpl.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/PseudoClassImpl.java	Fri Feb 22 15:41:59 2013 -0500
@@ -24,48 +24,19 @@
  */
 package com.sun.javafx.css;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import javafx.css.PseudoClass;
 
 /**
  * Implementation details of {@link javafx.css.PseudoClass}
  */
-public final class PseudoClassImpl extends PseudoClass {
+final class PseudoClassImpl extends PseudoClass {
 
-    /**
-     * @see javafx.css.PseudoClass#getPseudoClassName(String)
-     */
-    public static PseudoClass getPseudoClassImpl(String pseudoClass) {
 
-        if (pseudoClass == null || pseudoClass.trim().isEmpty()) {
-            throw new IllegalArgumentException("pseudoClass cannot be null or empty String");
-        }
-
-        PseudoClassImpl instance = null;
-        
-        final Integer value = pseudoClassMap.get(pseudoClass);
-        final int index = value != null ? value.intValue() : -1;
-        
-        final int size = pseudoClasses.size();
-        assert index < size;
-        
-        if (index != -1 && index < size) {
-            instance = pseudoClasses.get(index);
-        }
-        
-        if (instance == null) {
-            instance = new PseudoClassImpl(pseudoClass, size);
-            pseudoClasses.add(instance);
-            pseudoClassMap.put(pseudoClass, Integer.valueOf(size));
-        }
-        
-        return instance;
+    PseudoClassImpl(String pseudoClassName, int index) {
+        this.pseudoClassName = pseudoClassName;
+        this.index = index;
     }
 
-
     /** @return the pseudo-class state */
     @Override
     public String getPseudoClassName() {
@@ -73,26 +44,17 @@
     }
 
     /** @return the pseudo-class state */
-   @Override public String toString() {
+    @Override public String toString() {
         return pseudoClassName;
     }
 
-    /** Cannot create an instance of State except through PseudoClass static methods */
-    private PseudoClassImpl(String pseudoClassName, int index) {
-        this.pseudoClassName = pseudoClassName;
-        this.index = index;
+    public int getIndex() {
+       return index;
     }
 
-    final String pseudoClassName;
+    private final String pseudoClassName;
 
     // index of this PseudoClass in pseudoClasses list.
-    final int index;
-    
-    // package private for unit test purposes
-    static final Map<String,Integer> pseudoClassMap = 
-            new HashMap<String,Integer>(64);
-
-    static final List<PseudoClassImpl> pseudoClasses =
-            new ArrayList<PseudoClassImpl>();
-    
+    private final int index;
+   
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/PseudoClassSet.java	Tue Feb 19 14:07:57 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,593 +0,0 @@
-/*
- * 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 java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import javafx.css.PseudoClass;
-
-/**
- * States represents a set of State. A {@code Node} may be in more than
- * one pseudo-class state. {@code States} is used to aggregate the active
- * pseudo-class state of a {@code Node}.
- */
-class PseudoClassSet implements Set<PseudoClass> {
-
-    /** {@inheritDoc} */
-    @Override
-    public int size() {
-
-        int size = 0;
-        if (pseudoClasses.length > 0) {
-            for (int n = 0; n < pseudoClasses.length; n++) {
-                final long mask = pseudoClasses[n];
-                if (mask != 0) {
-                    size += Long.bitCount(mask);
-                }
-            }
-        }
-        // index.length is zero or all index[n] values are zero
-        return size;
-
-    }
-
-    @Override
-    public boolean isEmpty() {
-        
-        if (pseudoClasses.length > 0) {
-            for (int n = 0; n < pseudoClasses.length; n++) {
-                final long mask = pseudoClasses[n];
-                if (mask != 0) {
-                    return false;
-                }
-            }
-        }
-        // index.length is zero or all index[n] values are zero
-        return true;
-
-    }
-
-    /**
-     * {@inheritDoc} This returned iterator is not fail-fast.
-     */
-    @Override
-    public Iterator<PseudoClass> iterator() {
-        
-        return new Iterator<PseudoClass>() {
-            int next = -1;
-            int element = 0;
-            int index = -1;
-            
-            @Override
-            public boolean hasNext() {
-                if (pseudoClasses == null || pseudoClasses.length == 0) {
-                    return false;
-                }
-
-                boolean found = false;
-                
-                do {
-                    long bit = 0;
-                    if (++next >= Long.SIZE) {
-                        if (++element < pseudoClasses.length) {
-                            next = 0;
-                            bit = 1;
-                        } else {
-                            return false;
-                        }
-                    }                        
-                    
-                    bit = 1l << next;
-                    found = (bit & pseudoClasses[element]) == bit;
-                    
-                } while( !found );
-                
-                if (found) {
-                    index = Long.SIZE * element + next;
-                }
-                return found;
-            }
-
-            @Override
-            public PseudoClass next() {
-                try {
-                    return PseudoClassImpl.pseudoClasses.get(index);
-                } catch (IndexOutOfBoundsException e) {
-                    throw new NoSuchElementException("["+element+"]["+next+"]");
-                }
-            }
-
-            @Override
-            public void remove() {
-                try {
-                    PseudoClassImpl impl = PseudoClassImpl.pseudoClasses.get(index);
-                    PseudoClassSet.this.remove(impl);
-                } catch (IndexOutOfBoundsException e) {
-                    throw new NoSuchElementException("["+element+"]["+next+"]");
-                }
-            }
-        };
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public Object[] toArray() {
-        return toArray(new PseudoClass[size()]);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public <T> T[] toArray(T[] a) {
-        if (a.length < size()) {
-            a = (T[]) new PseudoClass[size()];
-        }
-        int index = 0;
-        final List<PseudoClassImpl> pseudoClasses = PseudoClassImpl.pseudoClasses;
-        for (int n=0, nMax=pseudoClasses.size(); n<nMax; n++) {
-            PseudoClassImpl impl = pseudoClasses.get(n);
-            if (contains(impl)) {
-                a[index++] = (T) impl;
-            }
-        }
-        return a;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean add(PseudoClass e) {
-        
-        if (e == null) {
-            // this not modified!
-            return false;
-        }
-
-        PseudoClassImpl impl = cast(e);
-        
-        final int element = impl.index / Long.SIZE;
-        final long bit = 1l << (impl.index % Long.SIZE);
-        
-        // need to grow?
-        if (element >= pseudoClasses.length) {
-            final long[] temp = new long[element + 1];
-            System.arraycopy(pseudoClasses, 0, temp, 0, pseudoClasses.length);
-            pseudoClasses = temp;
-        }
-        
-        final Long temp = pseudoClasses[element];
-        pseudoClasses[element] = temp | bit;
-        
-        // if index[element] == temp, then the bit was already set
-        final boolean modified = (pseudoClasses[element] != temp);
-        return modified;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean remove(Object o) {
-        
-        if (o == null) {
-            // this not modified!
-            return false;
-        }
-
-        PseudoClassImpl impl = cast(o);
-
-        final int element = impl.index / Long.SIZE;
-        final long bit = 1l << (impl.index % Long.SIZE);
-
-        if (element >= pseudoClasses.length) {
-            // not in this Set!
-            return false;
-        }
-        
-        final Long temp = pseudoClasses[element];
-        pseudoClasses[element] = temp & ~bit;
-
-        // if index[element] == temp, then the bit was not there
-        final boolean modified = (pseudoClasses[element] != temp);
-        return modified;
-    }
-
-    
-    /** {@inheritDoc} */
-    @Override
-    public boolean contains(Object o) {
-        if (o == null) {
-            return false;
-        }
-        
-        final PseudoClassImpl impl = cast(o);
-
-        final int element = impl.index / Long.SIZE;
-        final long bit = 1l << (impl.index % Long.SIZE);
-
-        return (element < pseudoClasses.length) && (pseudoClasses[element] & bit) == bit;
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    public boolean containsAll(Collection<?> c) {
-
-        if (c == null) {
-            // this not modified!
-            return false;
-        }
-        
-        if (c instanceof PseudoClassSet) {
-            
-            PseudoClassSet other = (PseudoClassSet)c;
-            
-            // this contains all of other if both are empty
-            if (pseudoClasses.length == 0 && other.pseudoClasses.length == 0) {
-                return true;
-            }
-            // [foo] cannot contain all of [foo bar]
-            if (pseudoClasses.length < other.pseudoClasses.length) {
-                return false;
-            }
-            // does [foo bar bang] contain all of [foo bar]?
-            for (int n = 0, max = other.pseudoClasses.length; n < max; n++) {
-                if ((pseudoClasses[n] & other.pseudoClasses[n]) != other.pseudoClasses[n]) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        
-        // [foo] cannot contain all of [foo bar]
-        if (size() < c.size()) {
-            return false;
-        }
-
-        // The hard way...        
-        for (Iterator<?> iter = c.iterator(); iter.hasNext();) {
-            final PseudoClass pseudoClass = (PseudoClass) iter.next();
-            if (!contains(pseudoClass)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean addAll(Collection<? extends PseudoClass> c) {
-        
-        if (c == null) {
-            // this not modified!
-            return false;
-        }
-        
-        boolean modified = false;
-        
-        if (c instanceof PseudoClassSet) {
-            
-            PseudoClassSet other = (PseudoClassSet)c;
-            boolean triggerTransition = false;
-            
-            if (other.isEmpty()) {
-                // this not modified!
-                return false;
-            } 
-            
-            final long[] maskOne = this.pseudoClasses;
-            final long[] maskTwo = other.pseudoClasses;
-
-            final int max = Math.max(maskOne.length, maskTwo.length);
-            final long[] union = new long[max];
-
-            for(int n = 0; n < max; n++) {
-                if (n < maskOne.length && n < maskTwo.length) {
-                    union[n] = maskOne[n] | maskTwo[n];
-                } else if (n < maskOne.length) {
-                    union[n] = maskOne[n];
-                } else {
-                    union[n] = maskTwo[n];
-                }
-                
-                final boolean different = (union[n] != maskOne[n]);
-                modified |= different;
-
-                if (!triggerTransition && different) {
-                    if (n < triggerStates.length) {
-                        triggerTransition = (union[n] & triggerStates[n]) != 0;
-                    }
-                }
-            }
-            if (modified) {
-                this.pseudoClasses = union;
-            }
-            return modified;
-        }
-        
-        // The hard way...
-        for (Iterator<?> iter = c.iterator(); iter.hasNext();) {
-            final PseudoClass pseudoClass = (PseudoClass) iter.next();
-            modified |= add(pseudoClass);
-        }
-        return modified;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean retainAll(Collection<?> c) {
-
-        if (c == null) {
-            // this not modified!
-            return false;
-        }
-        
-        boolean modified = false;
-        if (c instanceof PseudoClassSet) {
-            
-            PseudoClassSet other = (PseudoClassSet)c;
-            boolean triggerTransition = false;
-            
-            if (other.isEmpty()) {
-                // this not modified!
-                return false;
-            }
-
-            final long[] maskOne = this.pseudoClasses;
-            final long[] maskTwo = other.pseudoClasses;
-
-            final int max = Math.min(maskOne.length, maskTwo.length);
-            for(int n = 0; n < max; n++) {
-                long temp = maskOne[n] & maskTwo[n];
-                
-                boolean different = temp != maskOne[n];
-                modified |= different;
-                
-                if (!triggerTransition && different) {
-                    if (n < triggerStates.length) {
-                        triggerTransition = (temp & triggerStates[n]) != 0;
-                    }
-                }
-                
-                maskOne[n] = temp; 
-            }
-            
-            return modified;
-        }
-        
-        for (Iterator<?> iter = iterator(); iter.hasNext();) {
-            final PseudoClass pseudoClass = (PseudoClass) iter.next();
-            if (!c.contains(pseudoClass)) {
-                modified |= remove(pseudoClass);
-            }
-        }
-        return modified;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean removeAll(Collection<?> c) {
-        
-        if (c == null) {
-            // this not modified!
-            return false;
-        }
-        
-        boolean modified = false;
-        
-        if (c instanceof PseudoClassSet) {
-            
-            PseudoClassSet other = (PseudoClassSet)c;
-            boolean triggerTransition = false; 
-            
-            if (other.isEmpty()) {
-                // this was not modified!
-                return false;
-            }
-
-            final long[] maskOne = pseudoClasses;
-            final long[] maskTwo = other.pseudoClasses;
-
-            final int max = Math.min(maskOne.length, maskTwo.length);
-            for(int n = 0; n < max; n++) {
-                long temp = maskOne[n] & ~maskTwo[n];
-
-                boolean different = temp != maskOne[n];
-                modified |= different;
-                
-                if (!triggerTransition && different) {
-                    if (n < triggerStates.length) {
-                        triggerTransition = (maskOne[n] & triggerStates[n]) != 0;
-                    }
-                }
-                
-                maskOne[n] = temp;
-            }
-
-            return modified;            
-        }
-        
-        // the hard way...
-        if (size() <= c.size()) {
-            for (Iterator<?> iter = c.iterator(); iter.hasNext();) {
-                final PseudoClass pseudoClass = (PseudoClass) iter.next();
-                if (contains(pseudoClass)) {
-                    modified |= remove(pseudoClass);
-                }
-            }
-        } else {
-            for (Iterator<?> iter = iterator(); iter.hasNext();) {
-                final PseudoClass pseudoClass = (PseudoClass) iter.next();
-                if (c.contains(pseudoClass)) {
-                    modified |= remove(pseudoClass);
-                }
-            }
-        }
-        return modified;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void clear() {
-        pseudoClasses = new long[1];
-    }
-    
-    boolean isTransition(PseudoClass e) {
-
-        boolean isTransition = false;
-        
-        PseudoClassImpl impl = cast(e);
-
-        final int element = impl.index / Long.SIZE;
-        final long bit = 1l << (impl.index % Long.SIZE);
-        
-        if (element < triggerStates.length) {
-            final long m = triggerStates[element];
-            isTransition = (m & bit) == bit;
-        }
-        
-        return isTransition;
-        
-    }
-
-    /** @return The list of PseudoClass that are represented by this States object */
-    public List<PseudoClass> getPseudoClasses() {
-        final List<PseudoClass> list = new ArrayList<PseudoClass>();
-        final List<PseudoClassImpl> pclases = PseudoClassImpl.pseudoClasses;
-        for (int n=0, nMax=pclases.size(); n<nMax; n++) {
-            final PseudoClassImpl impl = pclases.get(n);
-            if (contains(impl)) {
-                list.add(impl);
-            }
-        }
-        return list;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 71 * hash + Arrays.hashCode(this.pseudoClasses);
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final PseudoClassSet other = (PseudoClassSet) obj;
-        if (!Arrays.equals(this.pseudoClasses, other.pseudoClasses)) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        final List<PseudoClass> list = getPseudoClasses();
-        if (list != null) {
-            return list.toString();
-        } else {
-            return "[]";
-        }
-    }
-
-   static List<PseudoClass> getPseudoClasses(long[] masks) {
-        final List<PseudoClass> pseudoClasses = new ArrayList<PseudoClass>();
-        for (int n=0; n<masks.length; n++) {
-            for (int l=0; l<Long.SIZE; l++) {
-                long bit = 1l << l;
-                if ((masks[n] & bit) == bit) {
-                    int index = n*Long.SIZE + l;
-                    if (index < PseudoClassImpl.pseudoClasses.size()) {
-                        pseudoClasses.add(PseudoClassImpl.pseudoClasses.get(index));                        
-                    }
-                }                    
-            }
-        }
-        return pseudoClasses;
-   }
-    
-   static long[] addPseudoClass(long[] pseudoClasses, int pseudoClassIndex) {
-       
-        final int index = (pseudoClassIndex / Long.SIZE);
-        final long bit   = 1l << (pseudoClassIndex % Long.SIZE);
-        
-        long[] temp = pseudoClasses;
-        if (temp == null || temp.length <= index) {
-            temp = new long[index+1];
-            System.arraycopy(pseudoClasses, 0, temp, 0, pseudoClasses.length);
-        }
-        
-        temp[index] |= bit;       
-        return temp;
-   }
-   
-   static boolean containsPseudoClass(long[] pseudoClasses, int pseudoClassIndex) {
-       
-        final int index = (pseudoClassIndex / Long.SIZE);
-        final long bit   = 1l << (pseudoClassIndex % Long.SIZE);
-        
-        if (pseudoClasses == null || index < pseudoClasses.length) {
-            return false;
-        }
-        
-        return (pseudoClasses[index] & bit) == bit;
-   }
-   
-   private long[] EMPTY_SET = new long[0];
-    /** Create an empty set of PseudoClass */
-    protected PseudoClassSet() {
-        this.pseudoClasses = EMPTY_SET;
-        this.triggerStates = EMPTY_SET;
-    }
-
-    /*
-     * Try to cast the arg to a PseudoClassImpl.
-     * @throws ClassCastException if the class of the argument is
-     *         is not a PseudoClass
-     * @throws NullPointerException if the argument is null
-     */
-    private PseudoClassImpl cast(Object o) {
-        if (o == null) {
-            throw new NullPointerException("null arg");
-        }
-        PseudoClass pseudoClass = (PseudoClass) o;
-        PseudoClassImpl impl = (pseudoClass instanceof PseudoClassImpl) 
-            ? (PseudoClassImpl) pseudoClass 
-            : (PseudoClassImpl) PseudoClassImpl.getPseudoClassImpl(pseudoClass.getPseudoClassName());
-        return impl;
-    }
-
-    // the set
-    long[] pseudoClasses;
-
-    // masks of state that, if changed, will trigger a css state transition
-    long[] triggerStates;
-    
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/css/PseudoClassState.java	Fri Feb 22 15:41:59 2013 -0500
@@ -0,0 +1,176 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javafx.css.PseudoClass;
+
+/**
+ * States represents a set of State. A {@code Node} may be in more than
+ * one pseudo-class state. {@code States} is used to aggregate the active
+ * pseudo-class state of a {@code Node}.
+ */
+public final class PseudoClassState extends BitSet<PseudoClass> implements Set<PseudoClass> {
+
+    /** Create an empty set of PseudoClass */
+    public PseudoClassState() {
+        super();
+    }
+
+    PseudoClassState(List<String> pseudoClassNames) {
+        super();
+        
+        int nMax = pseudoClassNames != null ? pseudoClassNames.size() : 0;
+        for(int n=0; n<nMax; n++) {
+            final PseudoClass sc = getPseudoClass(pseudoClassNames.get(n));
+            add(sc);
+        }
+    }           
+    
+    /** {@inheritDoc} */
+    @Override
+    public Object[] toArray() {
+        return toArray(new PseudoClass[size()]);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size()) {
+            a = (T[]) new PseudoClass[size()];
+        }
+        int index = 0;
+        while(index < getBits().length) {
+            final long state = getBits()[index];
+            for(int bit=0; bit<Long.SIZE; bit++) {
+                long mask = 1l << bit;
+                if ((state & mask) == mask) {
+                    int n = index * Long.SIZE + bit;
+                    PseudoClass impl = getPseudoClass(n);
+                    a[index++] = (T) impl;
+                }
+                    
+            }
+        }
+        return a;
+    }
+
+
+    @Override
+    public String toString() {
+        List<String> strings = new ArrayList<String>();
+        Iterator<PseudoClass> iter = iterator();
+        while (iter.hasNext()) {
+            strings.add(iter.next().getPseudoClassName());
+        }
+        return strings.toString();
+    }
+   
+    @Override
+    protected PseudoClass cast(Object o) {
+        if (o == null) {
+            throw new NullPointerException("null arg");
+        }
+        PseudoClass pseudoClass = (PseudoClass) o;
+        return pseudoClass;
+    }
+    
+    @Override
+    protected PseudoClass getT(int index) {
+        return getPseudoClass(index);
+    }
+
+    @Override
+    protected int getIndex(PseudoClass t) {
+        
+        if (t instanceof PseudoClassImpl) {
+            return ((PseudoClassImpl)t).getIndex();
+        }
+        
+        final String pseudoClass = t.getPseudoClassName();
+        Integer index = pseudoClassMap.get(pseudoClass);
+        
+        if (index == null) {
+            index = Integer.valueOf(pseudoClasses.size());
+            pseudoClasses.add(new PseudoClassImpl(pseudoClass, index.intValue()));
+            pseudoClassMap.put(pseudoClass, index);        
+        }
+        return index.intValue();
+        
+    }
+
+   
+    /**
+     * @see javafx.css.PseudoClass#getPseudoClassName(String)
+     */
+    public static PseudoClass getPseudoClass(String pseudoClass) {
+
+        if (pseudoClass == null || pseudoClass.trim().isEmpty()) {
+            throw new IllegalArgumentException("pseudoClass cannot be null or empty String");
+        }
+
+        PseudoClass instance = null;
+        
+        final Integer value = pseudoClassMap.get(pseudoClass);
+        final int index = value != null ? value.intValue() : -1;
+        
+        final int size = pseudoClasses.size();
+        assert index < size;
+        
+        if (index != -1 && index < size) {
+            instance = pseudoClasses.get(index);
+        }
+        
+        if (instance == null) {
+            instance = new PseudoClassImpl(pseudoClass, size);
+            pseudoClasses.add(instance);
+            pseudoClassMap.put(pseudoClass, Integer.valueOf(size));
+        }
+        
+        return instance;
+    }
+   
+    static PseudoClass getPseudoClass(int index) {
+       if (0 <= index && index < pseudoClasses.size()) {
+           return pseudoClasses.get(index);
+       }
+       return null;
+    }
+   
+    // package private for unit test purposes
+    static final Map<String,Integer> pseudoClassMap = 
+            new HashMap<String,Integer>(64);
+
+    static final List<PseudoClass> pseudoClasses =
+            new ArrayList<PseudoClass>();
+     
+}
+
--- a/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Fri Feb 22 15:41:59 2013 -0500
@@ -29,12 +29,12 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 import javafx.collections.ListChangeListener.Change;
 import javafx.collections.ObservableList;
+import javafx.css.PseudoClass;
 import javafx.css.StyleOrigin;
-import javafx.css.PseudoClass;
 
 import javafx.scene.Node;
 import javafx.scene.Scene;
@@ -125,24 +125,12 @@
         return matches;
     }
 
-    final List<Match> matches(Scene scene) {
-        List<Match> matches = new ArrayList<Match>();
-        for (int i = 0; i < selectors.size(); i++) {
-            Selector sel = selectors.get(i);
-            Match match = sel.matches(scene);
-            if (match != null) {
-                matches.add(match);
-            }
-        }
-        return matches;
-    }
-
     // Return mask of selectors that match
-    long applies(Node node, long[][] pseudoclassBits) {
+    long applies(Node node, Set<PseudoClass>[] triggerStates) {
         long mask = 0;
         for (int i = 0; i < selectors.size(); i++) {
             Selector sel = selectors.get(i);
-            if (sel.applies(node, pseudoclassBits, 0)) {                
+            if (sel.applies(node, triggerStates, 0)) {                
                 mask |= 1l << i;
             }
         }
--- a/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Fri Feb 22 15:41:59 2013 -0500
@@ -34,7 +34,6 @@
 import javafx.css.PseudoClass;
 
 import javafx.scene.Node;
-import javafx.scene.Scene;
 
 /**
  * Used by CSSRule to determine whether or not the rule applies to a 
@@ -61,18 +60,18 @@
      *      for no match
      */
     abstract Match matches(Node node);
-    abstract Match matches(Scene scene);
+
     // 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);
+    abstract boolean applies(Node node, Set<PseudoClass>[] triggerStates, int bit);
     
     /**
      * Determines whether the current state of the node and its parents
      * matches the pseudo-classes defined (if any) for this selector.
      */
-    abstract boolean stateMatches(Node node, long[] state);
+    public abstract boolean stateMatches(Node node, Set<PseudoClass> state);
 
     private static final int TYPE_SIMPLE = 1;
     private static final int TYPE_COMPOUND = 2;
--- a/javafx-ui-common/src/com/sun/javafx/css/SelectorPartitioning.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/SelectorPartitioning.java	Fri Feb 22 15:41:59 2013 -0500
@@ -40,101 +40,101 @@
      * 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;
-        }
-        
-    }
+//    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
@@ -380,11 +380,11 @@
                 ? new PartitionKey(selectorType)
                 : null;
         
-        final long[] selectorStyleClass = simpleSelector.getStyleClassMasks();
+        final Set<StyleClass> selectorStyleClass = simpleSelector.getStyleClassSet();
         final boolean hasStyleClass = 
-            (selectorStyleClass != null && selectorStyleClass.length > 0);
+            (selectorStyleClass != null && selectorStyleClass.size() > 0);
         final PartitionKey styleClassKey = hasStyleClass 
-                ? new PartitionKey<StyleClassKey>(new StyleClassKey(selectorStyleClass))
+                ? new PartitionKey<Set<StyleClass>>(selectorStyleClass)
                 : null;
         
         final int c = 
@@ -428,7 +428,7 @@
     }
     
     /** Get the list of rules that match this selector. Package accessible */
-    List<Rule> match(String selectorId, String selectorType, long[] selectorStyleClass) {
+    List<Rule> match(String selectorId, String selectorType, Set<StyleClass> selectorStyleClass) {
         
         final boolean hasId = 
             (selectorId != null && selectorId.isEmpty() == false);
@@ -443,9 +443,9 @@
                 : null;
         
         final boolean hasStyleClass = 
-            (selectorStyleClass != null && selectorStyleClass.length > 0);
+            (selectorStyleClass != null && selectorStyleClass.size() > 0);
         final PartitionKey styleClassKey = hasStyleClass 
-                ? new PartitionKey<StyleClassKey>(new StyleClassKey(selectorStyleClass))
+                ? new PartitionKey<Set<StyleClass>>(selectorStyleClass)
                 : null;
         
         int c = 
@@ -476,10 +476,10 @@
                                 slot.copyRules(ruleData);
 
                                 if ((c & STYLECLASS_BIT) == STYLECLASS_BIT) {
-                                    StyleClassKey key = (StyleClassKey)styleClassKey.key;
+                                    Set<StyleClass> key = (Set<StyleClass>)styleClassKey.key;
                                     for (Slot s : slot.referents.values()) {
-                                        StyleClassKey other = (StyleClassKey)s.partition.key.key;
-                                        if (other.isSubsetOf(key)) {
+                                        Set<StyleClass> other = (Set<StyleClass>)s.partition.key.key;
+                                        if (key.containsAll(other)) {
                                             s.copyRules(ruleData);
                                         }
                                     }
@@ -516,10 +516,10 @@
                             partition.copyRules(ruleData);
 
                             if ((c & STYLECLASS_BIT) == STYLECLASS_BIT) {
-                                StyleClassKey key = (StyleClassKey)styleClassKey.key;
+                                Set<StyleClass> key = (Set<StyleClass>)styleClassKey.key;
                                 for (Slot s : partition.slots.values()) {
-                                    StyleClassKey other = (StyleClassKey)s.partition.key.key;
-                                    if (other.isSubsetOf(key)) {
+                                    Set<StyleClass> other = (Set<StyleClass>)s.partition.key.key;
+                                    if (key.containsAll(other)) {
                                         s.copyRules(ruleData);
                                     }
                                 }
--- a/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Fri Feb 22 15:41:59 2013 -0500
@@ -28,7 +28,14 @@
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import javafx.css.PseudoClass;
 import javafx.geometry.NodeOrientation;
 import static javafx.geometry.NodeOrientation.*;
@@ -41,105 +48,6 @@
  */
 final public class SimpleSelector extends Selector {
     
-    //
-    // 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:
@@ -160,15 +68,23 @@
      * @return Immutable List&lt;String&gt; of style-classes of the selector
      */
     public List<String> getStyleClasses() {
-        return getStyleClassStrings(styleClassMasks);
+        
+        final List<String> names = new ArrayList<String>();
+        
+        Iterator<StyleClass> iter = styleClassSet.iterator();
+        while (iter.hasNext()) {
+            names.add(iter.next().getStyleClassName());
+        }
+        
+        return Collections.unmodifiableList(names);
     }
 
-    long[] getStyleClassMasks() {
-        return styleClassMasks;
+    Set<StyleClass> getStyleClassSet() {
+        return styleClassSet;
     }
     
     /** styleClasses converted to a set of bit masks */
-    final private long[] styleClassMasks;
+    final private StyleClassSet styleClassSet;
     
     final private String id;
     /*
@@ -179,20 +95,22 @@
     }
     
     // a mask of bits corresponding to the pseudoclasses
-    final private long[] pseudoClassStates;
+    final private PseudoClassState pseudoClassState;
     
-    long[] getPseudoClassStates() {
-        return pseudoClassStates;
+    Set<PseudoClass> getPseudoClassStates() {
+        return pseudoClassState;
     }
 
     /**
      * @return Immutable List&lt;String&gt; of pseudo-classes of the selector
      */
     public List<String> getPseudoclasses() {
-        final List<PseudoClass> pclasses = PseudoClassSet.getPseudoClasses(pseudoClassStates);
+        
         final List<String> names = new ArrayList<String>();
-        for (PseudoClass pclass : pclasses) {
-            names.add(pclass.getPseudoClassName());
+        
+        Iterator<PseudoClass> iter = pseudoClassState.iterator();
+        while (iter.hasNext()) {
+            names.add(iter.next().getPseudoClassName());
         }
         
         if (nodeOrientation == RIGHT_TO_LEFT) {
@@ -231,16 +149,27 @@
         // then match needs to check name
         this.matchOnName = (name != null && !("".equals(name)) && !("*".equals(name)));
 
-        this.styleClassMasks = 
-                (styleClasses != null && styleClasses.isEmpty() == false)
-                ? getStyleClassMasks(styleClasses)
-                : new long[0];
-        this.matchOnStyleClass = (this.styleClassMasks.length > 0);
+        this.styleClassSet = new StyleClassSet();
+        
+        int nMax = styleClasses != null ? styleClasses.size() : 0;
+        for(int n=0; n<nMax; n++) { 
+            
+            final String styleClassName = styleClasses.get(n);
+            if (styleClassName == null || styleClassName.isEmpty()) continue;
+            
+            final StyleClass styleClass = StyleClassSet.getStyleClass(styleClassName);
+            this.styleClassSet.add(styleClass);
+        }
+        
+        this.matchOnStyleClass = (this.styleClassSet.size() > 0);
 
-        final int nMax = pseudoClasses != null ? pseudoClasses.size() : 0;
-        long[] temp = new long[0];
+        this.pseudoClassState = new PseudoClassState();
+        
+        nMax = pseudoClasses != null ? pseudoClasses.size() : 0;
+
         NodeOrientation dir = NodeOrientation.INHERIT;
         for(int n=0; n<nMax; n++) { 
+            
             final String pclass = pseudoClasses.get(n);
             if (pclass == null || pclass.isEmpty()) continue;
             
@@ -251,11 +180,10 @@
                 continue;
             }
             
-            final PseudoClassImpl impl = 
-                (PseudoClassImpl)PseudoClassImpl.getPseudoClassImpl(pclass);
-            temp = PseudoClassSet.addPseudoClass(temp, impl.index);
+            final PseudoClass pseudoClass = PseudoClassState.getPseudoClass(pclass);
+            this.pseudoClassState.add(pseudoClass);
         }
-        this.pseudoClassStates = temp;
+        
         this.nodeOrientation = dir;
         this.id = id == null ? "" : id;
         // if id is not null and not empty, then match needs to check id
@@ -263,28 +191,28 @@
 
     }
     
-    /** copy constructor used by StyleManager */
+    /** copy constructor used by StyleManager
     SimpleSelector(final SimpleSelector other) {
         
         this.name = other.name;
         this.matchOnName = other.matchOnName;
-        
+        this.styleClassSet = new StyleClass
         if (other.matchOnStyleClass) {
-            final int length = other.styleClassMasks.length;
-            final long[] src = other.styleClassMasks;
-            final long[] dest = this.styleClassMasks = new long[length];
+            final int length = other.styleClassSet.length;
+            final long[] src = other.styleClassSet;
+            final long[] dest = this.styleClassSet = new long[length];
             System.arraycopy(src, 0, dest, 0, length);
         } else {
             // other is long[0]
-            this.styleClassMasks = other.styleClassMasks;
+            this.styleClassSet = other.styleClassSet;
         }
         this.matchOnStyleClass = other.matchOnStyleClass;
         
-        this.pseudoClassStates = other.pseudoClassStates;
+        this.pseudoClassState = other.pseudoClassState;
         this.nodeOrientation = other.nodeOrientation;
         this.id = other.id;
         this.matchOnId = other.matchOnId;
-    }
+    } */
 
     /**
      * Returns a {@link Match} if this selector matches the specified object, or 
@@ -298,31 +226,8 @@
     Match matches(final Node node) {
         if (applies(node)) {
             final int idCount = (matchOnId) ? 1 : 0;
-            int styleClassCount = 0;
-            for (int n=0; n<styleClassMasks.length; n++) {
-                styleClassCount += Long.bitCount(styleClassMasks[n] & VALUE_MASK);
-            }
-            return new Match(this, pseudoClassStates, idCount, styleClassCount);
-        }
-        return null;
-    }
-
-    @Override 
-    Match matches(final Scene scene) {
-        // Scene should match wildcard or specific java class name only.
-        if (!matchOnStyleClass 
-                && !matchOnId 
-                && (pseudoClassStates == null || pseudoClassStates.length == 0)) {
-
-            final String className = scene.getClass().getName();
-            final boolean classMatch =
-                "".equals(name) || nameMatchesAtEnd(className);
-
-            if (classMatch) {
-                // we know idCount and styleClassCount are zero from
-                // the condition for entering the outer block
-                return new Match(this, pseudoClassStates, 0, 0 );
-            }
+            int styleClassCount = styleClassSet.size();
+            return new Match(this, pseudoClassState, idCount, styleClassCount);
         }
         return null;
     }
@@ -364,10 +269,18 @@
 
         if (matchOnStyleClass) {
             
-            final StyleHelper styleHelper = node.impl_getStyleHelper();
-            final long[] otherStyleClassBits = styleHelper.getStyleClassBits();
-        
-            boolean styleClassMatch = matchStyleClasses(otherStyleClassBits); 
+            final StyleClassSet otherStyleClassSet = new StyleClassSet();
+            final List<String> styleClasses = node.getStyleClass();
+            for(int n=0, nMax = styleClasses.size(); n<nMax; n++) { 
+
+                final String styleClassName = styleClasses.get(n);
+                if (styleClassName == null || styleClassName.isEmpty()) continue;
+
+                final StyleClass styleClass = StyleClassSet.getStyleClass(styleClassName);
+                otherStyleClassSet.add(styleClass);
+            }
+            
+            boolean styleClassMatch = matchStyleClasses(otherStyleClassSet); 
             if (!styleClassMatch) return false;
         }
         
@@ -375,31 +288,28 @@
     }
     
     @Override 
-    boolean applies(Node node, long[][] pseudoClasses, int depth) {
+    boolean applies(Node node, Set<PseudoClass>[] pseudoClasses, int depth) {
 
         
         final boolean applies = applies(node);
+        
         //
         // We only need the pseudo-classes if the selector applies to the node.
         // 
         if (applies && pseudoClasses != null && depth < pseudoClasses.length) {
-            // make sure states[depth] can hold this selectors pseudo-class states
-            if (pseudoClasses[depth] == null || pseudoClasses[depth].length < pseudoClassStates.length) {
-                long[] temp = new long[pseudoClassStates.length];
-                if (pseudoClasses[depth] != null) {
-                    System.arraycopy(pseudoClasses[depth], 0, temp, 0, pseudoClasses[depth].length);
-                }
-                pseudoClasses[depth] = temp;
+
+            if (pseudoClasses[depth] == null) {
+                pseudoClasses[depth] = new PseudoClassState();
             }
-            for (int n=0; n<pseudoClassStates.length; n++) {
-                pseudoClasses[depth][n] |= this.pseudoClassStates[n];
-            }
+            
+            pseudoClasses[depth].addAll(pseudoClassState);
+            
         }
         return applies;
     }
 
     // todo - is this used?
-    private boolean mightApply(final String className, final String id, long[] styleClasses) {
+    private boolean mightApply(final String className, final String id, StyleClassSet styleClasses) {
         if (matchOnName && nameMatchesAtEnd(className)) return true;
         if (matchOnId   && this.id.equals(id)) return true;
         if (matchOnStyleClass) return matchStyleClasses(styleClasses);
@@ -407,10 +317,10 @@
     }
     
     @Override
-    boolean stateMatches(final Node node, long[] states) {
+    public boolean stateMatches(final Node node, Set<PseudoClass> states) {
         // [foo bar] matches [foo bar bang], 
         // but [foo bar bang] doesn't match [foo bar]
-        return isSubsetOf(pseudoClassStates, states);
+        return states != null ? states.containsAll(pseudoClassState) : false;
     }
 
     /*
@@ -445,36 +355,8 @@
     //
     // This rule matches when class="pastoral blue aqua marine" but does not
     // match for class="pastoral blue".
-    private boolean matchStyleClasses(long[] nodeStyleClasses) {
-        return isSubsetOf(styleClassMasks, nodeStyleClasses);
-    }
-
-    /** 
-      * return true if seq1 is a subset of seq2. That is, all the strings
-      * in seq1 are contained in 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;
-        
-        // they are a subset if both are empty
-        if (seq1.length == 0 && seq2.length == 0) return true;
-
-        // [foo bar] cannot be a subset of [foo]
-        if (seq1.length > seq2.length) return false;
-
-        // 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;
-            // is slower than the following... 
-            final long m1 = seq1[n];
-            final long m2 = m1 & seq2[n];
-            if (m1 != m2) return false;
-        }
-        return true;
-
+    private boolean matchStyleClasses(StyleClassSet otherStyleClasses) {
+        return otherStyleClasses.containsAll(styleClassSet);
     }
 
     @Override
@@ -492,51 +374,47 @@
         if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
             return false;
         }
-        if (this.styleClassMasks != other.styleClassMasks && 
-                (this.styleClassMasks == null || 
-                    !Arrays.equals(this.styleClassMasks, other.styleClassMasks))) {
+        if (this.styleClassSet.equals(other.styleClassSet) == false) {
             return false;
         }
-        if (this.pseudoClassStates != null ? other.pseudoClassStates == null : other.pseudoClassStates != null) {
+        if (this.pseudoClassState.equals(other.pseudoClassState) == false) {
             return false;
         } 
         
-        return  Arrays.equals(this.pseudoClassStates,other.pseudoClassStates);
+        return true;
     }
 
-    private  int hash = -1;
     /* Hash code is used in Style's hash code and Style's hash 
        code is used by StyleHelper */
     @Override public int hashCode() {
-        if (hash == -1) {
-            hash = name.hashCode();
-            hash = 31 * (hash + (styleClassMasks != null ? Arrays.hashCode(styleClassMasks) : 37));
-            hash = 31 * (hash + (id != null ? id.hashCode() : 1229));
-            hash = 31 * (hash + (pseudoClassStates != null ? pseudoClassStates.hashCode() : 0));
-        }
+        int hash = 7;
+        hash = 31 * (hash + name.hashCode());
+        hash = 31 * (hash + styleClassSet.hashCode());
+        hash = 31 * (hash + styleClassSet.hashCode());
+        hash = (id != null) ? 31 * (hash + id.hashCode()) : 0;
+        hash = 31 * (hash + pseudoClassState.hashCode());
         return hash;
     }
 
     /** Converts this object to a string. */
     @Override public String toString() {
+        
         StringBuilder sbuf = new StringBuilder();
         if (name != null && name.isEmpty() == false) sbuf.append(name);
         else sbuf.append("*");
-        if (styleClassMasks != null && styleClassMasks.length > 0) {
-            List<String> strings = getStyleClassStrings(styleClassMasks);
-            for(String styleClass : strings) {
-                sbuf.append('.');
-                sbuf.append(styleClass);
-            }
+        Iterator<StyleClass> iter1 = styleClassSet.iterator();
+        while(iter1.hasNext()) {
+            final StyleClass styleClass = iter1.next();
+            sbuf.append('.').append(styleClass.getStyleClassName());
         }
         if (id != null && id.isEmpty() == false) {
             sbuf.append('#');
             sbuf.append(id);
         }
-        List<String> pseudoclasses = getPseudoclasses();
-        for (int n=0; n<pseudoclasses.size(); n++) {
-            sbuf.append(':');
-            sbuf.append(pseudoclasses.get(n));
+        Iterator<PseudoClass> iter2 = pseudoClassState.iterator();
+        while(iter2.hasNext()) {
+            final PseudoClass pseudoClass = iter2.next();
+            sbuf.append(':').append(pseudoClass.getPseudoClassName());
         }
             
         return sbuf.toString();
@@ -547,13 +425,19 @@
     {
         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(styleClassSet.size());
+        Iterator<StyleClass> iter1 = styleClassSet.iterator();
+        while(iter1.hasNext()) {
+            final StyleClass sc = iter1.next();
+            os.writeShort(stringStore.addString(sc.getStyleClassName()));
+        }
         os.writeShort(stringStore.addString(id));
-        List<String> pseudoclasses = getPseudoclasses();
-        os.writeShort(pseudoclasses.size());
-        for (String p : pseudoclasses)  os.writeShort(stringStore.addString(p));
+        os.writeShort(pseudoClassState.size());
+        Iterator<PseudoClass> iter2 = pseudoClassState.iterator();
+        while(iter2.hasNext()) {
+            final PseudoClass pc = iter2.next();
+            os.writeShort(stringStore.addString(pc.getPseudoClassName()));
+        }
     }
 
     static SimpleSelector readBinary(final DataInputStream is, final String[] strings)
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleCache.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleCache.java	Fri Feb 22 15:41:59 2013 -0500
@@ -97,12 +97,13 @@
     
     public static final class Key {
         
-        public Key(int[] styleMapIds) {
-            this.styleMapIds = Arrays.copyOf(styleMapIds, styleMapIds.length);
+        public Key(int[] styleMapIds, int count) {
+            this.styleMapIds = new int[count];
+            System.arraycopy(styleMapIds, 0, this.styleMapIds, 0, count);
         }
         
         public Key(Key other) {
-            this.styleMapIds = Arrays.copyOf(other.styleMapIds, other.styleMapIds.length);
+            this(other.styleMapIds, other.styleMapIds != null ? other.styleMapIds.length : 0);
         }
 
         @Override
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleCacheEntry.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleCacheEntry.java	Fri Feb 22 15:41:59 2013 -0500
@@ -27,6 +27,8 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
+import javafx.css.PseudoClass;
 import javafx.css.StyleOrigin;
 
 /**
@@ -47,12 +49,12 @@
         this.values = new HashMap<String,CalculatedValue>();
     }
     
-    public CalculatedValue getRelativeFont() {
-        return relativeFont;
+    public CalculatedValue getFont() {
+        return font;
     }
     
-    public void setRelativeFont(CalculatedValue relativeFont) {
-        this.relativeFont = relativeFont;
+    public void setFont(CalculatedValue font) {
+        this.font = font;
     }
     
     public CalculatedValue get(String property) {
@@ -79,8 +81,8 @@
         final boolean isLocal =
             (cv.getOrigin() == StyleOrigin.INLINE || cv.getOrigin() == StyleOrigin.USER)            
             || (cv.isRelative() &&
-                (relativeFont.getOrigin() == StyleOrigin.INLINE || 
-                 relativeFont.getOrigin() == StyleOrigin.USER));
+                (font.getOrigin() == StyleOrigin.INLINE || 
+                 font.getOrigin() == StyleOrigin.USER));
                 
 
         if (isLocal) {
@@ -116,17 +118,20 @@
     
     public final static class Key {
 
-        private final long[][] pseudoClassStates;
+        private final Set<PseudoClass>[] pseudoClassStates;
     
-        public Key(long[][] pseudoClassStates) {
-            this.pseudoClassStates = pseudoClassStates;
+        public Key(Set<PseudoClass>[] pseudoClassStates, int count) {
+                        
+            this.pseudoClassStates = new PseudoClassState[count];
+            
+            for (int n=0; n<count; n++) {
+                this.pseudoClassStates[n] = new PseudoClassState();
+                this.pseudoClassStates[n].addAll(pseudoClassStates[n]);
+            }
         }
         
         private Key(Key other) {
-            this.pseudoClassStates = new long[other.pseudoClassStates.length][0];
-            for (int n=0; n<other.pseudoClassStates.length; n++) {
-                this.pseudoClassStates[n] = Arrays.copyOf(other.pseudoClassStates[n], other.pseudoClassStates[n].length);                
-            }
+            this(other.pseudoClassStates, other.pseudoClassStates != null ? other.pseudoClassStates.length : 0);
         }
 
         @Override
@@ -136,12 +141,9 @@
             
             for (int i=0; i<iMax; i++) {
                 
-                final long[] states = pseudoClassStates[i];
-                if (states == null) continue;
-                
-                for (int j=0; j<states.length; j++) {
-                    final long l = states[j];
-                    hash = 67 * hash + (int)(l^(l>>>32));
+                final Set<PseudoClass> states = pseudoClassStates[i];
+                if (states != null) {                
+                    hash = 67 * hash + states.hashCode();
                 }
             }
             return hash;
@@ -173,26 +175,13 @@
             
             for (int i=0; i<pseudoClassStates.length; i++) {
                 
-                final long[] ts = pseudoClassStates[i];
-                final long[] os = other.pseudoClassStates[i];
+                final Set<PseudoClass> this_pcs = pseudoClassStates[i];
+                final Set<PseudoClass> other_pcs = other.pseudoClassStates[i];
                 
                 // if one is null, the other must be too
-                if ((ts == null) ^ (os == null)) {
+                if (this_pcs == null ? other_pcs != null : !this_pcs.equals(other_pcs)) {
                     return false;
                 }
-                
-                // if one is null, the other is too
-                if (ts == null) {
-                    continue;
-                }
-                
-                if (ts.length != os.length) {
-                    return false;
-                }
-                
-                for (int j=0; j<ts.length; j++) {
-                    if (ts[j] != os[j]) return false;
-                }
             }
             
             return true;
@@ -203,5 +192,5 @@
     private final StyleCache.Key sharedCacheKey;
     private final StyleCacheEntry.Key sharedEntryKey;
     private final Map<String,CalculatedValue> values;
-    private CalculatedValue  relativeFont; // for use in converting relative sizes
+    private CalculatedValue  font; // for use in converting font relative sizes
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleClass.java	Fri Feb 22 15:41:59 2013 -0500
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011, 2013, 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;
+
+/**
+ * 
+ */
+final class StyleClass {
+
+
+    StyleClass(String styleClassName, int index) {
+        this.styleClassName = styleClassName;
+        this.index = index;
+    }
+
+    /** @return the style-class */
+    public String getStyleClassName() {
+        return styleClassName;
+    }
+
+    /** @return the style-class */
+    @Override public String toString() {
+        return styleClassName;
+    }
+
+    public int getIndex() {
+       return index;
+    }
+
+    private final String styleClassName;
+
+    // index of this StyleClass in styleClasses list.
+    private final int index;
+   
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleClassSet.java	Fri Feb 22 15:41:59 2013 -0500
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2011, 2013, 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.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * States represents a set of State. A {@code Node} may be in more than
+ * one pseudo-class state. {@code States} is used to aggregate the active
+ * pseudo-class state of a {@code Node}.
+ */
+public final class StyleClassSet  extends BitSet<StyleClass> implements Set<StyleClass> {
+
+    /** Create an empty set of StyleClass */
+    public StyleClassSet() {
+        super();
+    }
+    
+    StyleClassSet(List<String> styleClassNames) {
+
+        int nMax = styleClassNames != null ? styleClassNames.size() : 0;
+        for(int n=0; n<nMax; n++) {
+            final StyleClass sc = getStyleClass(styleClassNames.get(n));
+            add(sc);
+        }
+
+    }    
+    
+    /** {@inheritDoc} */
+    @Override
+    public Object[] toArray() {
+        return toArray(new StyleClass[size()]);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size()) {
+            a = (T[]) new StyleClass[size()];
+        }
+        int index = 0;
+        while(index < getBits().length) {
+            final long state = getBits()[index];
+            for(int bit=0; bit<Long.SIZE; bit++) {
+                long mask = 1l << bit;
+                if ((state & mask) == mask) {
+                    int n = index * Long.SIZE + bit;
+                    StyleClass impl = getStyleClass(n);
+                    a[index++] = (T) impl;
+                }
+                    
+            }
+        }
+        return a;
+    }
+
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("style-classes: [");
+        Iterator<StyleClass> iter = iterator();
+        while (iter.hasNext()) {
+            builder.append(iter.next().getStyleClassName());
+            if (iter.hasNext()) {
+                builder.append(", ");
+            }
+        }
+        builder.append(']');        
+        return builder.toString();
+    }
+   
+    @Override
+    protected StyleClass cast(Object o) {
+        if (o == null) {
+            throw new NullPointerException("null arg");
+        }
+        StyleClass styleClass = (StyleClass) o;
+        return styleClass;
+    }
+    
+    @Override
+    protected StyleClass getT(int index) {
+        return getStyleClass(index);
+    }
+
+    @Override
+    protected int getIndex(StyleClass t) {
+        
+        if (t instanceof StyleClass) {
+            return ((StyleClass)t).getIndex();
+        }
+        
+        final String styleClass = t.getStyleClassName();
+        Integer index = styleClassMap.get(styleClass);
+        
+        if (index == null) {
+            index = Integer.valueOf(styleClasses.size());
+            styleClasses.add(new StyleClass(styleClass, index.intValue()));
+            styleClassMap.put(styleClass, index);        
+        }
+        return index.intValue();
+        
+    }
+
+   
+    /**
+     * @see javafx.css.StyleClass#getStyleClassName(String)
+     */
+    static StyleClass getStyleClass(String styleClass) {
+
+        if (styleClass == null || styleClass.trim().isEmpty()) {
+            throw new IllegalArgumentException("styleClass cannot be null or empty String");
+        }
+
+        StyleClass instance = null;
+        
+        final Integer value = styleClassMap.get(styleClass);
+        final int index = value != null ? value.intValue() : -1;
+        
+        final int size = styleClasses.size();
+        assert index < size;
+        
+        if (index != -1 && index < size) {
+            instance = styleClasses.get(index);
+        }
+        
+        if (instance == null) {
+            instance = new StyleClass(styleClass, size);
+            styleClasses.add(instance);
+            styleClassMap.put(styleClass, Integer.valueOf(size));
+        }
+        
+        return instance;
+    }
+
+   static StyleClass getStyleClass(int index) {
+       if (0 <= index && index < styleClasses.size()) {
+           return styleClasses.get(index);
+       }
+       return null;
+   }
+   
+    // package private for unit test purposes
+    static final Map<String,Integer> styleClassMap = 
+            new HashMap<String,Integer>(64);
+
+    static final List<StyleClass> styleClasses =
+            new ArrayList<StyleClass>();
+     
+}
+
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Tue Feb 19 14:07:57 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2201 +0,0 @@
-/*
- * 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.Logging;
-import com.sun.javafx.Utils;
-import static com.sun.javafx.css.CalculatedValue.SKIP;
-import com.sun.javafx.css.StyleManager.StyleMap;
-import com.sun.javafx.css.converters.FontConverter;
-import com.sun.javafx.css.parser.CSSParser;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.collections.ObservableMap;
-import javafx.css.CssMetaData;
-import javafx.css.FontCssMetaData;
-import javafx.css.PseudoClass;
-import javafx.css.StyleConverter;
-import javafx.css.StyleOrigin;
-import javafx.css.Styleable;
-import javafx.css.StyleableProperty;
-import javafx.scene.Node;
-import javafx.scene.Parent;
-import javafx.scene.text.Font;
-import javafx.scene.text.FontPosture;
-import javafx.scene.text.FontWeight;
-import sun.util.logging.PlatformLogger;
-
-/**
- * The StyleHelper is a helper class used for applying CSS information to Nodes.
- * In theory a single StyleHelper can be reused among all Nodes which share the
- * 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 final class StyleHelper {
-
-    private static final PlatformLogger LOGGER = com.sun.javafx.Logging.getCSSLogger();
-
-    /**
-     * Creates a new StyleHelper.
-     */
-    public StyleHelper(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(Node node) {
-
-        // Reset to initial state. If we end up with
-        // no styles, inline or otherwise, then transitionToState 
-        // will be a no-op.
-        styleClassBits = SimpleSelector.getStyleClassMasks(node.getStyleClass());
-        pseudoClassStates.triggerStates = EMPTY_BITS;
-        internalState = null;        
-        
-        // 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
-        // pseudo-class states that have styles. The StyleHelper's
-        // pseudoclassStateMask is a bitmask of those pseudoclasses that
-        // appear in the node's StyleHelper's smap. This list of
-        // pseudo-class masks is held by the StyleCacheKey. When a node is
-        // styled, its pseudoclasses and the pseudoclasses of its parents
-        // are gotten. By comparing the actual pseudo-class state to the
-        // pseudo-class states that apply, a CacheEntry can be created or
-        // fetched using only those pseudoclasses that matter.
-        final long[][] pclassMasks = new long[depth][0];
-        
-        final StyleManager.StyleMap styleMap = 
-                StyleManager.getInstance().findMatchingStyles(node, pclassMasks);
-
-        
-        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 inlineStyle = node.getStyle();
-            if (inlineStyle == null || inlineStyle.trim().isEmpty()) {
-                boolean mightInherit = false;
-                final List<CssMetaData<? extends Styleable, ?>> props = node.getCssMetaData();
-                final int pMax = props != null ? props.size() : 0;
-                for (int p=0; p<pMax; p++) {
-                    final CssMetaData<? extends Styleable, ?> prop = props.get(p);
-                    if (prop.isInherits()) {
-                        mightInherit = true;
-                        break;
-                    }
-                }
-                if (mightInherit == false) {
-                    return;
-                }
-            }
-        }   
-        
-        pseudoClassStates.triggerStates = Arrays.copyOf(pclassMasks[0], pclassMasks[0].length);
-
-        // make sure parent's transition states include the pseudo-classes 
-        // found when matching selectors
-        parent = node.getParent();
-        for(int n=1; n<depth; n++) {
-
-            final StyleHelper parentHelper = parent.impl_getStyleHelper();            
-            long[] states = parentHelper.pseudoClassStates.triggerStates;            
-            final long[] masks = pclassMasks[n];
-
-            // grow?
-            if (states == null || states.length < masks.length) {
-                long[] temp = new long[masks.length];
-                if (states != null) {
-                    System.arraycopy(states, 0, temp, 0, states.length);
-                }
-                states = parentHelper.pseudoClassStates.triggerStates = temp;
-            }
-            for (int m=0; m<masks.length; m++) {
-                states[m] |= masks[m];
-            }
-
-            parent = parent.getParent();
-        }         
-        
-        internalState = new InternalState(node, styleMap, pclassMasks);
-    }
-    
-    private InternalState internalState;
-        
-    private final static class InternalState {
-
-        // Set internal internalState structures
-        private InternalState(
-                Node node, 
-                StyleManager.StyleMap styleMap, 
-                long[][] pclassMasks) {
-
-            final int depth = pclassMasks.length;
-
-            int[] smapIds = new int[depth];
-            smapIds[0] = this.smapId = styleMap.id;
-            Parent parent = node.getParent();
-            for(int k=1; k<depth; k++) {
-                final StyleHelper helper = parent.impl_getStyleHelper();
-                if (helper.internalState == null) continue;
-                smapIds[k] = helper.internalState.smapId;
-                parent = parent.getParent();
-            }
-
-            this.styleCacheKey = new StyleCache.Key(smapIds); 
-
-            this.localStyleCache = new StyleCache();
-            
-            this.pclassMask = pclassMasks;
-            
-            CssMetaData<Styleable,Font> styleableFontProperty = null;
-            
-            final List<CssMetaData<? extends Styleable, ?>> props = node.getCssMetaData();
-            final int pMax = props != null ? props.size() : 0;
-            for (int p=0; p<pMax; p++) {
-                final CssMetaData<? extends Styleable, ?> prop = props.get(p);
-            
-                if ("-fx-font".equals(prop.getProperty())) {
-                    // unchecked!
-                    styleableFontProperty = (CssMetaData<Styleable, Font>) prop;
-                    break;
-                }
-            }
-
-            this.fontProp = styleableFontProperty;
-        
-        }
-                
-        private final CssMetaData<Styleable,Font> fontProp;
-        private final int smapId;
-        private final StyleCache.Key styleCacheKey;
-        private final StyleCache localStyleCache;
-        private final long[][] pclassMask;        
-        
-    }
-    
-    //
-    // Find the entry in local cache and in the shared cache that matches the states
-    private StyleCacheEntry getStyleCacheEntry(Node node, boolean[] isNewEntry) {
-
-        if (internalState == null) return null;
-        
-        //
-        // internalState.pclassMask is the set of pseudo-classes that appear
-        // in the style maps of this StyleHelper. Calculated values are
-        // cached by pseudo-class state, but only the pseudo-class states
-        // that mater are used in the search. So we take the transition states
-        // and intersect them with internalState.pclassMask to remove the
-        // transition states that don't matter when it comes to matching states
-        // on a  selector. For example if the style map contains only
-        // .foo:hover { -fx-fill: red; } then only the hover state matters
-        // but the transtion state could be [hover, focused]
-        //
-        final int depth = internalState.pclassMask.length;
-        final long[][] pclassMask = new long[depth][0];
-        
-        long[][] transitionStates = getTransitionStates(node, depth);
-
-        for (int n=0; n<depth; n++) {
-            // take the intersection of pclassMask[n] and states[n]
-            final long[] lscMask = internalState.pclassMask[n];
-            final long[] stateMask = transitionStates[n];
-            final int lMax = Math.min(stateMask.length, lscMask.length);
-            pclassMask[n] = new long[lMax];
-            for (int l=0; l<lMax; l++) {
-                final long m1 = stateMask[l];
-                final long m2 = lscMask[l];
-                // m1 is the current state of the node
-                // m2 is the states we care about
-                // pclassMask[n][l] should only be current state we care about
-                pclassMask[n][l] = m1 & m2;
-            }
-        }
-
-        StyleCacheEntry.Key key = new StyleCacheEntry.Key(pclassMask);
-                
-        // find the entry in the list with the same pclassMask
-        StyleCacheEntry localCacheEntry = internalState.localStyleCache.getStyleCacheEntry(key);
-
-        if (localCacheEntry == null) {
-            
-            if (isNewEntry != null && isNewEntry.length > 0) {
-                isNewEntry[0] = true;
-            }
-            
-            Map<String,CascadingStyle> inlineStyles = getInlineStyleMap(node);
-            
-            localCacheEntry = new StyleCacheEntry(internalState.styleCacheKey, key);
-            
-            final CalculatedValue relativeFont = 
-                getFontForUseInConvertingRelativeSize(node, localCacheEntry, getPseudoClassBits(), inlineStyles);            
-            
-            assert(relativeFont != null);
-            localCacheEntry.setRelativeFont(relativeFont);
-            
-            internalState.localStyleCache.putStyleCacheEntry(key, localCacheEntry);
-            
-        }
-        
-        return localCacheEntry;
-        
-    }
-    
-    public void inlineStyleChanged(Node node) {
-
-        // Clear local cache so styles will be recalculated. 
-        // Since we're clearing the cache and getting (potentially) 
-        // new styles, reset the properties to initial values.
-        if (internalState != null) {
-            
-            node.impl_cssResetInitialValues();
-            internalState.localStyleCache.clear();
-            
-            // do we have any styles at all now?
-            final String inlineStyle = node.getStyle();
-            if(inlineStyle == null && inlineStyle.isEmpty()) {
-
-                final Map<String, List<CascadingStyle>> smap = getStyleMap();            
-                if (smap == null || smap.isEmpty()) {
-                    // We have no styles! Reset this StyleHelper to its
-                    // initial state so that calls to transitionToState 
-                    // become a no-op.
-                    internalState = null;
-                }
-                
-                // If smap isn't empty, then there are styles that
-                // apply to the node. There isn't a need to remap the styles
-                // since we've only removed an inline style and inline styles
-                // aren't part of the style map.
-            }
-
-            
-            
-            
-        } else {
-            final String inlineStyle = node.getStyle();
-            if (inlineStyle == null || inlineStyle.isEmpty()) {
-                return;
-            }
-            // if we don't have a localStyleCache, that means this 
-            // node doesn't have any applicable styles and it didn't
-            // have an inline style before. If it did have an inline
-            // style before, then there would be an smap, albeit an
-            // an empty one. See setStyles for this bit of logic. 
-            // But now the  node does have an inline style and so it
-            // needs to have an smap and localStyleCache for the logic
-            // in transitionToState to work. 
-            Node parent = node;
-            int depth = 0;
-            while(parent != null) {
-                depth++;
-                parent = parent.getParent();
-            }
-
-            final long[][] pclassMasks = new long[depth][0];
-            internalState = new InternalState(node, StyleManager.StyleMap.EMPTY_MAP, pclassMasks);
-        }
-        
-    }
-        
-    private Map<String, List<CascadingStyle>> getStyleMap() {
-        if (internalState == null) return null;
-        StyleMap styleMap = StyleManager.getInstance().getStyleMap(internalState.smapId);
-        return (styleMap != null) ? styleMap.map : null;
-    }
-    
-    /** 
-     * The Node's style-class as bits.
-     */
-    private long[] styleClassBits = null;
-    long[] getStyleClassBits() {
-        return styleClassBits != null ? styleClassBits : EMPTY_BITS;
-    }
-
-    /**
-     * A convenient place for holding default values for populating the
-     * List&lt;Style&gt; that is populated if the Node has a 
-     * Map&lt;WritableValue&gt;, List&lt;Style&gt;. 
-     * See handleNoStyleFound
-     */
-    private static final Map<CssMetaData<? extends Styleable, ?>,Style> stylesFromDefaults = 
-            new HashMap<CssMetaData<? extends Styleable, ?>,Style>();
-    
-    /**
-     * The List to which Declarations fabricated from StyleablePropeerty 
-     * defaults are added.
-     */
-    private static final List<Declaration> declarationsFromDefaults;
-    
-    /**
-     * The Styles in defaultsStyles need to belong to a stylesheet. 
-     */
-    private static final Stylesheet defaultsStylesheet;
-    static {
-        final Rule defaultsRule = 
-            new Rule(new ArrayList<Selector>(), Collections.<Declaration>emptyList());
-        defaultsRule.getSelectors().add(Selector.getUniversalSelector());
-        declarationsFromDefaults = defaultsRule.getDeclarations();
-        defaultsStylesheet = new Stylesheet();
-        defaultsStylesheet.setOrigin(null);
-        defaultsStylesheet.getRules().add(defaultsRule);
-    };
-        
-    /** 
-     * Cache of parsed, inline styles. The key is Node.style. 
-     * The value is the set of property styles from parsing Node.style.
-     */
-    private static final Map<String,Map<String,CascadingStyle>> inlineStylesCache =
-        new HashMap<String,Map<String,CascadingStyle>>();
-
-    /**
-     * Get the map of property to style from the rules and declarations
-     * in the stylesheet. There is no need to do selector matching here since
-     * the stylesheet is from parsing Node.style.
-     */
-    private static Map<String,CascadingStyle> getInlineStyleMap(Stylesheet inlineStylesheet) {
-
-        final Map<String,CascadingStyle> inlineStyleMap = new HashMap<String,CascadingStyle>();
-        if (inlineStylesheet != null) {
-            // Order in which the declaration of a CascadingStyle appears (see below)
-            int ordinal = 0;
-            // For each declaration in the matching rules, create a CascadingStyle object
-            final List<Rule> stylesheetRules = inlineStylesheet.getRules();
-            for (int i = 0, imax = stylesheetRules.size(); i < imax; i++) {
-                final Rule rule = stylesheetRules.get(i);
-                final List<Declaration> declarations = rule.getDeclarations();
-                for (int k = 0, kmax = declarations.size(); k < kmax; k++) {
-                    Declaration decl = declarations.get(k);
-
-                    CascadingStyle s = new CascadingStyle(
-                        new Style(Selector.getUniversalSelector(), decl),
-                        EMPTY_BITS, // no pseudo classes
-                        0, // specificity is zero
-                        // 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++
-                    );
-
-                    inlineStyleMap.put(decl.property,s);
-                }
-            }
-        }
-        return inlineStyleMap;
-    }
-
-    /**
-     * Get the mapping of property to style from Node.style for this node.
-     */
-    private static Map<String,CascadingStyle> getInlineStyleMap(Styleable styleable) {
-        
-        final String inlineStyles = styleable.getStyle();
-
-        // If there are no styles for this property then we can just bail
-        if ((inlineStyles == null) || inlineStyles.isEmpty()) return null;
-
-        Map<String,CascadingStyle> styles = inlineStylesCache.get(inlineStyles);
-        
-        if (styles == null) {
-
-            Stylesheet inlineStylesheet =
-                CSSParser.getInstance().parseInlineStyle(styleable);
-            if (inlineStylesheet != null) {
-                inlineStylesheet.setOrigin(StyleOrigin.INLINE);
-            }
-            styles = getInlineStyleMap(inlineStylesheet);
-            
-            inlineStylesCache.put(inlineStyles, styles);
-        }
-
-        return styles;
-    }
-    
-    /**
-     * A Set of all the pseudo-class 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 pseudo-class state changes
-     * that are not in this hash set are ignored.
-     */
-    private PseudoClassSet pseudoClassStates = new PseudoClassSet();
-    
-    public Set<PseudoClass> getPseudoClassState() {
-        return Collections.unmodifiableSet(pseudoClassStates);
-    }
-
-    public boolean pseudoClassStateChanged(PseudoClass pseudoClass, boolean active) {
-    
-        boolean modified = false;
-        if (active) {
-            modified = pseudoClassStates.add(pseudoClass);
-        } else {
-            modified = pseudoClassStates.remove(pseudoClass);
-        }
-        
-        boolean isTransition = modified ? pseudoClassStates.isTransition(pseudoClass) : false;
-        return isTransition;
-    }    
-    
-    // get pseudo-class state for the node 
-    long[] getPseudoClassBits() {
-        return pseudoClassStates.pseudoClasses;
-    }
-    
-    /**
-     * dynamic pseudo-class state for this helper - only valid during a pulse. 
-     *
-     * 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.
-     *
-     */ 
-    private long[][] getTransitionStates(Node node, int depth) {
-
-        //
-        // Note Well: The array runs from leaf to root. That is, 
-        // transitionStates[0] is the pseudo-class state for node and 
-        // transitionStates[1..(states.length-1)] are the pseudoclassStates for the 
-        // node's parents.
-        //
-        
-        long[][] transitionStates = new long[depth][];
-        
-        Node parent = node;
-        int index = 0;
-        while (parent != null) {
-            
-            final StyleHelper helper = parent.impl_getStyleHelper();
-            long[] states = helper.pseudoClassStates.pseudoClasses;
-            transitionStates[index++] = (states != null) ? states : EMPTY_BITS;
-            
-            parent = parent.getParent();
-            
-        }
-        
-        return transitionStates;
-        
-    }
-    
-    ObservableMap<StyleableProperty<?>, List<Style>> observableStyleMap;
-     /**
-      * RT-17293
-      */
-     public final ObservableMap<StyleableProperty<?>, List<Style>> getObservableStyleMap() {
-         return observableStyleMap;
-     }
-
-     /**
-      * RT-17293
-      */
-     public final void setObservableStyleMap(ObservableMap<StyleableProperty<?>, List<Style>> observableStyleMap) {
-         this.observableStyleMap = observableStyleMap;
-     }
-          
-    
-    /**
-     * Called by the Node whenever it has transitioned from one set of
-     * pseudo-class states to another. This function will then lookup the
-     * new values for each of the styleable variables on the Node, 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(Node node) {
-       
-        if (internalState == null) {
-            return;
-        }
-        
-        final StyleMap smap = StyleManager.getInstance().getStyleMap(internalState.smapId);
-        if (smap == null) {
-            //
-            // If smap is null, then the StyleManager Cache from which
-            // this StyleHelper was created has been blown away and this
-            // StyleHelper is no good. If this is the case, we need to tell
-            // this node to reapply CSS
-            // 
-            internalState.localStyleCache.clear();
-            internalState = null;
-            node.impl_reapplyCSS();
-            return;
-            
-        }
-        //
-        // Styles that need lookup can be cached provided none of the styles
-        // are from Node.style.
-        //                
-        boolean[] isNewLocalCache = new boolean[] { false };
-        StyleCacheEntry cacheEntry = getStyleCacheEntry(node, isNewLocalCache);
-
-        assert(cacheEntry != null);
-        if (cacheEntry == null) {
-            internalState.localStyleCache.clear();
-            internalState = null;
-            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);
-        
-        
-        final StyleOrigin relativeFontOrigin = 
-                cacheEntry.getRelativeFont() != null 
-                ? cacheEntry.getRelativeFont().getOrigin() 
-                : null;
-        //
-        //
-        boolean fastpath = 
-                // If the cacheEntry is new, 
-                //   then calculate styles for this set of states
-                isNewLocalCache[0] == false &&
-                // If someone is watching the styles, 
-                //   then we have to take the slow path.
-                observableStyleMap == null &&
-                // If this node has inline-styles, 
-                //   then we might not be able to use the value in shared cache.
-                inlineStyles == null &&
-                // If the relative font came from a user-set value, 
-                //   then we might not be able to use the value in shared cache.
-                relativeFontOrigin != StyleOrigin.USER && 
-                // If the relative font came from an inline-style, 
-                //   then we might not be able to use the value in shared cache.
-                relativeFontOrigin != StyleOrigin.INLINE;
-        
-        
-        final List<CssMetaData<? extends Styleable, ?>> styleables = node.getCssMetaData();
-        
-        // Used in the for loop below, and a convenient place to stop when debugging.
-        final int max = styleables.size();
-
-        // RT-20643
-        CssError.setCurrentScene(node.getScene());
-        
-        // For each property that is settable, we need to do a lookup and
-        // transition to that value.
-        for(int n=0; n<max; n++) {
-
-            @SuppressWarnings("unchecked") // this is a widening conversion
-            final CssMetaData<Styleable,Object> cssMetaData = 
-                    (CssMetaData<Styleable,Object>)styleables.get(n);
-            
-            if (observableStyleMap != null) {
-                StyleableProperty<?> styleableProperty = cssMetaData.getStyleableProperty(node);
-                if (styleableProperty != null && observableStyleMap.containsKey(styleableProperty)) {
-                    observableStyleMap.remove(styleableProperty);
-                }
-            }
-            
-
-            // Skip the lookup if we know there isn't a chance for this property
-            // to be set (usually due to a "bind").
-            if (!cssMetaData.isSettable(node)) continue;
-
-            final String property = cssMetaData.getProperty();
-            
-            // Create a List to hold the Styles if the node has 
-            // a Map<WritableValue, List<Style>>
-            final List<Style> styleList = (observableStyleMap != null) 
-                    ? new ArrayList<Style>() 
-                    : null;
-
-            //
-            // if there are userStyles, then we cannot (at this time) use
-            // the cached value since the userStyles may contain a mapping for
-            // the lookup. At some point, I'd like to compare the userStyles
-            // with the lookups in the cached value. If userStyles doesn't
-            // have mappings for lookups, then the cached value could be used.
-            //
-            // cacheEntry may be null if the calculation of the style cache
-            // key would overflow long. In this case, the style simply cannot
-            // be cached.
-            //
-            // If the node has a style map, then we'll take the slow path. 
-            // This is so we don't have to cache the List<Style> that went 
-            // into figuring out the calculated value. The style map incurs a 
-            // performance penalty, but that is preferable to the memory hit
-            // if we had to cache the List<Style> - especially since asking
-            // for the List<Style> will be the exception rather than the rule.
-            //
-//            final boolean fastpath = styleList == null;
-            CalculatedValue calculatedValue = null;
-            if (fastpath) {
-
-                calculatedValue = cacheEntry.get(property);
-                if (calculatedValue == null) continue;
-
-            }
-
-            if (calculatedValue == null) {
-
-                boolean isUserSet = isUserSetProperty(node, cssMetaData);            
-
-                calculatedValue = lookup(node, cssMetaData, isUserSet, getPseudoClassBits(), 
-                        inlineStyles, node, cacheEntry, styleList);
-
-            }
-            
-            // RT-10522:
-            // If the user set the property and there is a style and
-            // the style came from the user agent stylesheet, then
-            // skip the value. A style from a user agent stylesheet should
-            // not override the user set style.
-            //
-            // RT-21894: the origin might be null if the calculatedValue 
-            // comes from reverting back to the initial value. In this case,
-            // make sure the initial value doesn't overwrite the user set value.
-            // Also moved this condition from the fastpath block to here since
-            // the check needs to be done on any calculated value, not just
-            // calculatedValues from cache
-            //
-            if (calculatedValue == SKIP
-                || (   calculatedValue != null
-                    && (   calculatedValue.getOrigin() == StyleOrigin.USER_AGENT
-                        || calculatedValue.getOrigin() == null) 
-                    && isUserSetProperty(node, cssMetaData)
-                    )
-                ) {
-                continue;
-            }
-            
-                final Object value = calculatedValue.getValue();
-                if (LOGGER.isLoggable(PlatformLogger.FINER)) {
-                    LOGGER.finer("call " + node + ".impl_cssSet(" +
-                                    property + ", " + value + ")");
-                }
-
-                try {
-                    cssMetaData.set(node, value, calculatedValue.getOrigin());
-                    
-                    cacheEntry.put(property, calculatedValue);
-
-                    
-                    if (observableStyleMap != null) {
-                        StyleableProperty<?> styleableProperty = cssMetaData.getStyleableProperty(node);                            
-                        observableStyleMap.put(styleableProperty, styleList);
-                    }
-                    
-                } catch (Exception e) {
-
-                    // RT-27155: if setting value raises exception, reset value 
-                    // the value to initial and thereafter skip setting the property
-                    cssMetaData.set(node, cssMetaData.getInitialValue(node), null);
-                    cacheEntry.put(property, SKIP);
-                    
-                    List<CssError> errors = null;
-                    if ((errors = StyleManager.getErrors()) != null) {
-                        final String msg = String.format("Failed to set css [%s] due to %s\n", cssMetaData, e.getMessage());
-                        final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
-                        errors.add(error);
-                    }
-                    // TODO: use logger here
-                    PlatformLogger logger = Logging.getCSSLogger();
-                    if (logger.isLoggable(PlatformLogger.WARNING)) {
-                        logger.warning(String.format("Failed to set css [%s]\n", cssMetaData), e);
-                    }
-                }
-
-            }
-        
-        // RT-20643
-        CssError.setCurrentScene(null);
-
-        // If the list weren't empty, we'd worry about animations at this
-        // point. TODO need to implement animation trickery here
-    }
-
-    /**
-     * Gets the CSS CascadingStyle for the property of this node in these pseudo-class
-     * states. A null style may be returned if there is no style information
-     * for this combination of input parameters.
-     *
-     * @param node 
-     * @param property
-     * @param states
-     * @return
-     */
-    private CascadingStyle getStyle(Node node, String property, long[] states, Map<String,CascadingStyle> inlineStyles){
-
-        assert node != null && property != null: String.valueOf(node) + ", " + String.valueOf(property);
-
-        final CascadingStyle inlineStyle = (inlineStyles != null) ? inlineStyles.get(property) : null;
-
-        // Get all of the Styles which may apply to this particular property
-        final Map<String, List<CascadingStyle>> smap = getStyleMap();
-        if (smap == null) return inlineStyle;
-
-        final List<CascadingStyle> styles = smap.get(property);
-
-        // If there are no styles for this property then we can just bail
-        if ((styles == null) || styles.isEmpty()) return inlineStyle;
-
-        // Go looking for the style. We do this by visiting each CascadingStyle in
-        // order finding the first that matches the current node & set of
-        // pseudo-class states. We use an iteration style that avoids creating
-        // garbage iterators (and wish javac did it for us...)
-       CascadingStyle style = null;
-        final int max = (styles == null) ? 0 : styles.size();
-        for (int i=0; i<max; i++) {
-            final CascadingStyle s = styles.get(i);
-            final Selector sel = s == null ? null : s.getSelector();
-            if (sel == null) continue; // bail if the selector is null.
-//System.out.println(node.toString() + "\n\tstates=" + PseudoClassSet.getPseudoClasses(states) + "\n\tstateMatches? " + sel.stateMatches(node, states) + "\n\tsel=" + sel.toString());            
-            if (sel.stateMatches(node, states)) {
-                style = s;
-                break;
-            }
-        }
-        
-        if (inlineStyle != null) {
-
-            // is inlineStyle more specific than style?    
-            if (style == null || inlineStyle.compareTo(style) < 0) {
-                style = inlineStyle;
-            }
-
-        }
-        return style;
-    }
-
-    /**
-     * The main workhorse of this class, the lookup method walks up the CSS
-     * style tree looking for the style information for the Node, the
-     * property associated with the given styleable, in these states for this font.
-     *
-     * @param node
-     * @param styleable
-     * @param states
-     * @param font
-     * @return
-     */
-    private CalculatedValue lookup(Node node, CssMetaData styleable, 
-            boolean isUserSet, long[] states,
-            Map<String,CascadingStyle> userStyles, Node originatingNode, 
-            StyleCacheEntry cacheEntry, List<Style> styleList) {
-
-        if (styleable.getConverter() == FontConverter.getInstance()) {
-        
-            return lookupFont(node, styleable, isUserSet, 
-                    originatingNode, cacheEntry, styleList);
-        }
-        
-        final String property = styleable.getProperty();
-
-        // Get the CascadingStyle which may apply to this particular property
-        CascadingStyle style = getStyle(node, property, states, userStyles);
-
-        // If no style was found and there are no sub styleables, then there
-        // are no matching styles for this property. We will then either SKIP
-        // or we will INHERIT. We will inspect the default value for the styleable,
-        // and if it is INHERIT then we will inherit otherwise we just skip it.
-        final List<CssMetaData<? extends Styleable, ?>> subProperties = styleable.getSubProperties();
-        final int numSubProperties = (subProperties != null) ? subProperties.size() : 0;
-        if (style == null) {
-            
-            if (numSubProperties == 0) {
-                
-                return handleNoStyleFound(node, styleable, isUserSet, userStyles, 
-                        originatingNode, cacheEntry, styleList);
-                
-            } else {
-
-                // If style is null then it means we didn't successfully find the
-                // property we were looking for. However, there might be sub styleables,
-                // in which case we should perform a lookup for them. For example,
-                // there might not be a style for "font", but there might be one
-                // for "font-size" or "font-weight". So if the style is null, then
-                // we need to check with the sub-styleables.
-
-                // Build up a list of all SubProperties which have a constituent part.
-                // I default the array to be the size of the number of total
-                // sub styleables to avoid having the array grow.
-                Map<CssMetaData,Object> subs = null;
-                StyleOrigin origin = null;
-                
-                boolean isRelative = false;
-                
-                for (int i=0; i<numSubProperties; i++) {
-                    CssMetaData subkey = subProperties.get(i);
-                    CalculatedValue constituent = 
-                        lookup(node, subkey, isUserSet, states, userStyles, 
-                            originatingNode, cacheEntry, styleList);
-                    if (constituent != SKIP) {
-                        if (subs == null) {
-                            subs = new HashMap<CssMetaData,Object>();
-                        }
-                        subs.put(subkey, constituent.getValue());
-
-                        // origin of this style is the most specific
-                        if ((origin != null && constituent.getOrigin() != null)
-                                ? origin.compareTo(constituent.getOrigin()) < 0
-                                : constituent.getOrigin() != null) {
-                            origin = constituent.getOrigin();
-                        }
-                        
-                        // if the constiuent uses relative sizes, then 
-                        // isRelative is true;
-                        isRelative = isRelative || constituent.isRelative();
-                            
-                    }
-                }
-
-                // If there are no subkeys which apply...
-                if (subs == null || subs.isEmpty()) {
-                    return handleNoStyleFound(node, styleable, isUserSet, userStyles, 
-                            originatingNode, cacheEntry, styleList);
-                }
-
-                try {
-                    final StyleConverter keyType = styleable.getConverter();
-                    assert(keyType instanceof StyleConverterImpl);
-                    if (keyType instanceof StyleConverterImpl) {
-                        Object ret = ((StyleConverterImpl)keyType).convert(subs);
-                        return new CalculatedValue(ret, origin, isRelative);
-                    } else {
-                        return SKIP;
-                    }
-                } catch (ClassCastException cce) {
-                    final String msg = formatExceptionMessage(node, styleable, null, cce);
-                    List<CssError> errors = null;
-                    if ((errors = StyleManager.getErrors()) != null) {
-                        final CssError error = new CssError.PropertySetError(styleable, node, msg);
-                        errors.add(error);
-                    }
-                    if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
-                        LOGGER.warning("caught: ", cce);
-                        LOGGER.warning("styleable = " + styleable);
-                        LOGGER.warning("node = " + node.toString());
-                    }
-                    return SKIP;
-                }
-            }                
-            
-        } else { // style != null
-
-            // RT-10522:
-            // If the user set the property and there is a style and
-            // the style came from the user agent stylesheet, then
-            // skip the value. A style from a user agent stylesheet should
-            // not override the user set style.
-            if (isUserSet && style.getOrigin() == StyleOrigin.USER_AGENT) {
-                return SKIP;
-            }
-
-            // If there was a style found, then we want to check whether the
-            // value was "inherit". If so, then we will simply inherit.
-            final ParsedValueImpl cssValue = style.getParsedValueImpl();
-            if (cssValue != null && "inherit".equals(cssValue.getValue())) {
-                if (styleList != null) styleList.add(style.getStyle());
-                return inherit(node, styleable, userStyles, 
-                        originatingNode, cacheEntry, styleList);
-            }
-        }
-
-//        System.out.println("lookup " + property +
-//                ", selector = \'" + style.selector.toString() + "\'" +
-//                ", node = " + node.toString());
-
-        if (styleList != null) { 
-            styleList.add(style.getStyle());
-        }
-        
-        return calculateValue(style, node, styleable, states, userStyles, 
-                    originatingNode, cacheEntry, styleList);
-    }
-    
-    /**
-     * Called when there is no style found.
-     */
-    private CalculatedValue handleNoStyleFound(Node node, CssMetaData styleable,
-            boolean isUserSet, Map<String,CascadingStyle> userStyles, 
-            Node originatingNode, StyleCacheEntry cacheEntry, List<Style> styleList) {
-
-        if (styleable.isInherits()) {
-
-
-            // RT-16308: if there is no matching style and the user set 
-            // the property, do not look for inherited styles.
-            if (isUserSet) {
-
-                    return SKIP;
-                    
-            }
-
-            CalculatedValue cv =
-                inherit(node, styleable, userStyles, 
-                    originatingNode, cacheEntry, styleList);
-
-            return cv;
-
-        } else if (isUserSet) {
-
-            // Not inherited. There is no style but we don't want to
-            // set the default value if the user set the property
-            return SKIP;
-
-        } else {
-            
-            final Map<String, List<CascadingStyle>> smap = getStyleMap();
-            if (smap == null) return SKIP;
-            
-            if (smap.containsKey(styleable.getProperty())) {
-
-                // If there is a style in the stylemap but it just doen't apply,
-                // then it may have been set and it needs to be reset to its
-                // default value. For example, if there is a style for the hover
-                // pseudo-class state, but no style for the default state.
-                Object initialValue = styleable.getInitialValue(node);
-
-                if (styleList != null) {
-
-                    Style initialStyle = stylesFromDefaults.get(styleable);
-                    if (initialStyle != null) {
-                        if (!declarationsFromDefaults.contains(initialStyle.getDeclaration())) {
-                            declarationsFromDefaults.add(initialStyle.getDeclaration());
-                        }
-                    } else {
-                        initialStyle = new Style( 
-                            Selector.getUniversalSelector(),
-                            new Declaration(styleable.getProperty(), 
-                                        new ParsedValueImpl(initialValue, null), false));
-                        stylesFromDefaults.put(styleable, initialStyle);
-                        declarationsFromDefaults.add(initialStyle.getDeclaration());
-                    }
-
-                    styleList.add(initialStyle);
-                }
-
-                return new CalculatedValue(initialValue, null, false);
-
-            } else {
-
-                return SKIP;
-
-            }
-        }
-    }
-    /**
-     * Called when we must inherit a value from a parent node in the scenegraph.
-     */
-    private CalculatedValue inherit(Node node, CssMetaData styleable,
-            Map<String,CascadingStyle> userStyles, 
-            Node originatingNode, StyleCacheEntry cacheEntry, List<Style> styleList) {
-        
-        // Locate the first parentStyleHelper in the hierarchy
-        Node parent = node.getParent();        
-        StyleHelper parentStyleHelper = parent == null ? null : parent.impl_getStyleHelper();
-        while (parent != null && parentStyleHelper == null) {
-            parent = parent.getParent();
-            if (parent != null) {
-                parentStyleHelper = parent.impl_getStyleHelper();
-            }
-        }
-
-        if (parent == null) {
-            return SKIP;
-        }
-        return parentStyleHelper.lookup(parent, styleable, false,
-                parentStyleHelper.getPseudoClassBits(),
-                getInlineStyleMap(parent), originatingNode, cacheEntry, styleList);
-    }
-
-
-    private static final long[] EMPTY_BITS = new long[0];
-    
-    /**
-     * Find the property among the styles that pertain to the Node
-     */
-    private CascadingStyle resolveRef(Node node, String property, long[] states,
-            Map<String,CascadingStyle> inlineStyles) {
-        
-        final CascadingStyle style = getStyle(node, property, states, inlineStyles);
-        if (style != null) {
-            return style;
-        } else {
-            // if style is null, it may be because there isn't a style for this
-            // node in this state, or we may need to look up the parent chain
-            if (states != null && states.length > 0) {
-                // if states > 0, then we need to check this node again,
-                // but without any states.
-                return resolveRef(node,property,EMPTY_BITS,inlineStyles);
-            } else {
-                // TODO: This block was copied from inherit. Both should use same code somehow.
-                Node parent = node.getParent();
-                StyleHelper parentStyleHelper = parent == null ? null : parent.impl_getStyleHelper();
-                while (parent != null && parentStyleHelper == null) {
-                    parent = parent.getParent();
-                    if (parent != null) {
-                        parentStyleHelper = parent.impl_getStyleHelper();
-                    }
-                }
-
-                if (parent == null || parentStyleHelper == null) {
-                    return null;
-                }
-                return parentStyleHelper.resolveRef(parent, property,
-                        parentStyleHelper.getPseudoClassBits(),
-                        getInlineStyleMap(parent));
-            }
-        }
-    }
-
-    // to resolve a lookup, we just need to find the parsed value.
-    private ParsedValueImpl resolveLookups(
-            Node node, 
-            ParsedValueImpl value, 
-            long[] states,
-            Map<String,CascadingStyle> inlineStyles,
-            ObjectProperty<StyleOrigin> whence,
-            List<Style> styleList) {
-        
-        
-        assert(value instanceof ParsedValueImpl);
-        if ((value instanceof ParsedValueImpl) == false) { return value; }
-        
-        ParsedValueImpl parsedValue = (ParsedValueImpl)value;
-        
-        //
-        // either the value itself is a lookup, or the value contain a lookup
-        //
-        if (parsedValue.isLookup()) {
-
-            // The value we're looking for should be a Paint, one of the
-            // containers for linear, radial or ladder, or a derived color.
-            final Object val = parsedValue.getValue();
-            if (val instanceof String) {
-
-                final String sval = (String)val;
-                
-                CascadingStyle resolved = 
-                    resolveRef(node, sval, states, inlineStyles);
-
-                if (resolved != null) {
-                    
-                    if (styleList != null) {
-                        final Style style = resolved.getStyle();
-                        if (style != null && !styleList.contains(style)) {
-                            styleList.add(style);
-                        }
-                    }
-                    
-                    // The origin of this parsed value is the greatest of 
-                    // any of the resolved reference. If a resolved reference
-                    // comes from an inline style, for example, then the value
-                    // calculated from the resolved lookup should have inline
-                    // as its origin. Otherwise, an inline style could be 
-                    // stored in shared cache.
-                    final StyleOrigin wOrigin = whence.get();
-                    final StyleOrigin rOrigin = resolved.getOrigin();
-                    if (rOrigin != null && (wOrigin == null ||  wOrigin.compareTo(rOrigin) < 0)) {
-                        whence.set(rOrigin);
-                    } 
-                    
-                    // the resolved value may itself need to be resolved.
-                    // For example, if the value "color" resolves to "base",
-                    // then "base" will need to be resolved as well.
-                    return resolveLookups(node, resolved.getParsedValueImpl(), states, inlineStyles, whence, styleList);
-                }
-            }
-        }
-
-        // If the value doesn't contain any values that need lookup, then bail
-        if (!parsedValue.isContainsLookups()) {
-            return parsedValue;
-        }
-
-        final Object val = parsedValue.getValue();
-        if (val instanceof ParsedValueImpl[][]) {
-        // If ParsedValueImpl is a layered sequence of values, resolve the lookups for each.
-            final ParsedValueImpl[][] layers = (ParsedValueImpl[][])val;
-            for (int l=0; l<layers.length; l++) {
-                for (int ll=0; ll<layers[l].length; ll++) {
-                    if (layers[l][ll] == null) continue;
-                    layers[l][ll].resolved = 
-                        resolveLookups(node, layers[l][ll], states, inlineStyles, whence, styleList);
-                }
-            }
-
-        } else if (val instanceof ParsedValueImpl[]) {
-        // If ParsedValueImpl is a sequence of values, resolve the lookups for each.
-            final ParsedValueImpl[] layer = (ParsedValueImpl[])val;
-            for (int l=0; l<layer.length; l++) {
-                if (layer[l] == null) continue;
-                layer[l].resolved =
-                    resolveLookups(node, layer[l], states, inlineStyles, whence, styleList);
-            }
-        }
-
-        return parsedValue;
-
-    }
-    
-    private String getUnresolvedLookup(ParsedValueImpl resolved) {
-
-        Object value = resolved.getValue();
-
-        if (resolved.isLookup() && value instanceof String) {
-            return (String)value;
-        } 
-
-        if (value instanceof ParsedValueImpl[][]) {
-            final ParsedValueImpl[][] layers = (ParsedValueImpl[][])value;
-            for (int l=0; l<layers.length; l++) {
-                for (int ll=0; ll<layers[l].length; ll++) {
-                    if (layers[l][ll] == null) continue;
-                    String unresolvedLookup = getUnresolvedLookup(layers[l][ll]);
-                    if (unresolvedLookup != null) return unresolvedLookup;
-                }
-            }
-
-        } else if (value instanceof ParsedValueImpl[]) {
-        // If ParsedValueImpl is a sequence of values, resolve the lookups for each.
-            final ParsedValueImpl[] layer = (ParsedValueImpl[])value;
-            for (int l=0; l<layer.length; l++) {
-                if (layer[l] == null) continue;
-                String unresolvedLookup = getUnresolvedLookup(layer[l]);
-                if (unresolvedLookup != null) return unresolvedLookup;
-            }
-        }        
-        
-        return null;
-    }
-    
-    private String formatUnresolvedLookupMessage(Node node, CssMetaData styleable, Style style, ParsedValueImpl resolved) {
-        
-        // find value that could not be looked up
-        String missingLookup = resolved != null ? getUnresolvedLookup(resolved) : null;
-        if (missingLookup == null) missingLookup = "a lookup value";
-        
-        StringBuilder sbuf = new StringBuilder();
-        sbuf.append("Could not resolve '")
-            .append(missingLookup)
-            .append("'")
-            .append(" while resolving lookups for '")
-            .append(styleable.getProperty())
-            .append("'");
-        
-        final Rule rule = style != null ? style.getDeclaration().getRule(): null;
-        final Stylesheet stylesheet = rule != null ? rule.getStylesheet() : null;
-        final java.net.URL url = stylesheet != null ? stylesheet.getUrl() : null;
-        if (url != null) {
-            sbuf.append(" from rule '")
-                .append(style.getSelector())
-                .append("' in stylesheet ").append(url.toExternalForm());
-        } else if (stylesheet != null && StyleOrigin.INLINE == stylesheet.getOrigin()) {
-            sbuf.append(" from inline style on " )
-                .append(node.toString());            
-        }
-        
-        return sbuf.toString();
-    }
-
-    private String formatExceptionMessage(Node node, CssMetaData styleable, Style style, Exception e) {
-        
-        StringBuilder sbuf = new StringBuilder();
-        sbuf.append("Caught ")
-            .append(e.toString())
-            .append("'")
-            .append(" while calculating value for '")
-            .append(styleable.getProperty())
-            .append("'");
-        
-        final Rule rule = style != null ? style.getDeclaration().getRule(): null;
-        final Stylesheet stylesheet = rule != null ? rule.getStylesheet() : null;
-        final java.net.URL url = stylesheet != null ? stylesheet.getUrl() : null;
-        if (url != null) {
-            sbuf.append(" from rule '")
-                .append(style.getSelector())
-                .append("' in stylesheet ").append(url.toExternalForm());
-        } else if (stylesheet != null && StyleOrigin.INLINE == stylesheet.getOrigin()) {
-            sbuf.append(" from inline style on " )
-                .append(node.toString());            
-        }
-        
-        return sbuf.toString();
-    }
-    
-    
-    private CalculatedValue calculateValue(
-            final CascadingStyle style, 
-            final Node node, 
-            final CssMetaData cssMetaData, 
-            final long[] states,
-            final Map<String,CascadingStyle> inlineStyles, 
-            final Node originatingNode, 
-            final StyleCacheEntry cacheEntry, 
-            final List<Style> styleList) {
-
-        final ParsedValueImpl cssValue = style.getParsedValueImpl();
-        if (cssValue != null && !("null").equals(cssValue.getValue())) {
-
-            ObjectProperty<StyleOrigin> whence = new SimpleObjectProperty<StyleOrigin>(style.getOrigin());
-            final ParsedValueImpl resolved = 
-                resolveLookups(node, cssValue, states, inlineStyles, whence, styleList);
-            
-            try {
-                // The computed value
-                Object val = null;
-                CalculatedValue fontValue = null;
-
-                //
-                // Avoid using a font calculated from a relative size
-                // to calculate a font with a relative size. 
-                // For example:
-                // Assume the default font size is 13 and we have a style with
-                // -fx-font-size: 1.5em, then the cacheEntry font value will 
-                // have a size of 13*1.5=19.5. 
-                // Now, when converting that same font size again in response
-                // to looking up a value for -fx-font, we do not want to use
-                // 19.5 as the font for relative size conversion since this will
-                // yield a font 19.5*1.5=29.25 when really what we want is
-                // a font size of 19.5.
-                // In this situation, then, we use the font from the parent's
-                // cache entry.
-                final String property = cssMetaData.getProperty();
-                if (resolved.isNeedsFont() &&
-                    (cacheEntry.getRelativeFont() == null || cacheEntry.getRelativeFont().isRelative()) &&
-                    ("-fx-font".equals(property) ||
-                     "-fx-font-size".equals(property)))  {
-                    
-                    Node parent = node;
-                    CalculatedValue cachedFont = cacheEntry.getRelativeFont();
-                    while(parent != null) {
-                        
-                        final StyleCacheEntry parentCacheEntry = 
-                            getParentCacheEntry(parent);
-                        
-                        if (parentCacheEntry != null) {
-                            fontValue = parentCacheEntry.getRelativeFont();
-                        
-                            if (fontValue != null && fontValue.isRelative()) {
-
-                                // If cacheEntry.font is null, then we're here by 
-                                // way of getFontForUseInConvertingRelativeSize
-                                // If  the fontValue is not relative, then the
-                                // cacheEntry.font needs to be calculated. If
-                                // fontValue is relative, then we can use it as
-                                // is - this is a hack for Control and SkinBase
-                                // which share the same styles (hence the check
-                                // for parent == node).
-                                // TBD - should check that they are the same styles
-    //                                if (parent == node && childCacheEntry.font == null) {
-    //                                    return fontValue;
-    //                                } 
-
-                                if (cachedFont != null) {
-                                    final Font ceFont = (Font)cachedFont.getValue();
-                                    final Font fvFont = (Font)fontValue.getValue();
-                                    if (ceFont.getSize() != fvFont.getSize()) {
-                                        // if the font sizes don't match, then
-                                        // the fonts came from distinct styles,
-                                        // otherwise, we need another level of
-                                        // indirection
-                                        break;
-                                    }
-                                } 
-
-                                // cachedFont is null or the sizes match
-                                // (implies the fonts came from the same style)
-                                cachedFont = fontValue;
-
-                            } else if (fontValue != null) {
-                                // fontValue.isRelative() == false
-                                break;
-                            }
-                        }
-                        // try again
-                        parent = parent.getParent();
-                    }
-                }
-
-                // did we get a fontValue from the preceding block (from the hack)?
-                // if not, get it from our cachEntry or choose the default.cd
-                if (fontValue == null && cacheEntry != null) {
-                    fontValue = cacheEntry.getRelativeFont();
-                }
-                final Font font = (fontValue != null) ? (Font)fontValue.getValue() : Font.getDefault();
-
-
-                if (resolved.getConverter() != null)
-                    val = resolved.convert(font);
-                else
-                    val = cssMetaData.getConverter().convert(resolved, font);
-
-                final StyleOrigin origin = whence.get();
-                return new CalculatedValue(val, origin, resolved.isNeedsFont());
-                
-            } catch (ClassCastException cce) {
-                final String msg = formatUnresolvedLookupMessage(node, cssMetaData, style.getStyle(),resolved);
-                List<CssError> errors = null;
-                if ((errors = StyleManager.getErrors()) != null) {
-                    final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
-                    errors.add(error);
-                }
-                if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
-                    LOGGER.warning(msg);
-                    LOGGER.fine("node = " + node.toString());
-                    LOGGER.fine("cssMetaData = " + cssMetaData);
-                    LOGGER.fine("styles = " + getMatchingStyles(node, cssMetaData));
-                }
-                return SKIP;
-            } catch (IllegalArgumentException iae) {
-                final String msg = formatExceptionMessage(node, cssMetaData, style.getStyle(), iae);
-                List<CssError> errors = null;
-                if ((errors = StyleManager.getErrors()) != null) {
-                    final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
-                    errors.add(error);
-                }
-                if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
-                    LOGGER.warning("caught: ", iae);
-                    LOGGER.fine("styleable = " + cssMetaData);
-                    LOGGER.fine("node = " + node.toString());
-                }
-                return SKIP;
-            } catch (NullPointerException npe) {
-                final String msg = formatExceptionMessage(node, cssMetaData, style.getStyle(), npe);
-                List<CssError> errors = null;
-                if ((errors = StyleManager.getErrors()) != null) {
-                    final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
-                    errors.add(error);
-                }
-                if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
-                    LOGGER.warning("caught: ", npe);
-                    LOGGER.fine("styleable = " + cssMetaData);
-                    LOGGER.fine("node = " + node.toString());
-                }
-                return SKIP;
-            } finally {
-                resolved.nullResolved();
-            }
-                
-        }
-        // either cssValue was null or cssValue's value was "null"
-        return new CalculatedValue(null, style.getOrigin(), false);
-           
-    }
-    
-    /** return true if the origin of the property is USER */
-    private boolean isUserSetProperty(Node node, CssMetaData styleable) {
-        StyleableProperty styleableProperty = node != null ? styleable.getStyleableProperty(node) : null;
-        // writable could be null if this is a sub-property
-        StyleOrigin origin = styleableProperty != null ? styleableProperty.getStyleOrigin() : null;
-        return (origin == StyleOrigin.USER);    
-    }    
-            
-    private static final CssMetaData dummyFontProperty =
-            new FontCssMetaData<Node>("-fx-font", Font.getDefault()) {
-
-        @Override
-        public boolean isSettable(Node node) {
-            return true;
-        }
-
-        @Override
-        public StyleableProperty<Font> getStyleableProperty(Node node) {
-            return null;
-        }
-    };
-   
-    private StyleCacheEntry getParentCacheEntry(Node child) {
-
-        if (child == null) return null;
-        
-        StyleCacheEntry parentCacheEntry = null;
-        Node parent = child;
-        StyleHelper parentHelper = null;
-        
-        do {
-            parent = parent.getParent();
-            if (parent != null) {
-                parentHelper = parent.impl_getStyleHelper();
-                parentCacheEntry = parentHelper.getStyleCacheEntry(parent, null);                
-            }
-        } while (parent != null && parentCacheEntry == null);
-
-        return parentCacheEntry;
-    }
-   
-    private CalculatedValue getFontForUseInConvertingRelativeSize(
-             final Node node,
-             final StyleCacheEntry cacheEntry,
-            long[] pseudoclassState,
-            Map<String,CascadingStyle> inlineStyles)
-     {
-        
-        // To make the code easier to read, define CONSIDER_INLINE_STYLES as true. 
-        // Passed to lookupFontSubProperty to tell it whether or not 
-        // it should look for inline styles
-        final boolean CONSIDER_INLINE_STYLES = true;
-        
-        StyleOrigin origin = null;
-        Font foundFont = null;
-        CalculatedValue foundSize = null;
-        CalculatedValue foundShorthand = null;
-        boolean isRelative = false;
-         
-        // RT-20145 - if looking for font size and the node has a font, 
-        // use the font property's value if it was set by the user and
-        // there is not an inline or author style.
-        if (internalState.fontProp != null) {
-            StyleableProperty<Font> styleableProp = internalState.fontProp.getStyleableProperty(node);
-            StyleOrigin fpOrigin = styleableProp.getStyleOrigin();
-            if (fpOrigin == StyleOrigin.USER) {                
-                origin = fpOrigin;
-                foundFont = styleableProp.getValue();
-            }
-        } 
- 
-        final CascadingStyle fontShorthand =
-            getStyle(node, "-fx-font", pseudoclassState, inlineStyles);
-
-        if (fontShorthand != null) {
-            
-            final CalculatedValue cv = 
-                calculateValue(fontShorthand, node, dummyFontProperty, 
-                    pseudoclassState, inlineStyles, 
-                    node, cacheEntry, null);
-            
-            // If we don't have an existing font, or if the origin of the
-            // existing font is less than that of the shorthand, then
-            // take the shorthand. If the origins compare equals, then take 
-            // the shorthand since the fontProp value will not have been
-            // updated yet.
-            // Man, this drove me nuts!
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {
-                               
-                // cv could be SKIP
-                if (cv.getValue() instanceof Font) {
-                    origin = cv.getOrigin();
-                    foundShorthand = cv;
-                    foundFont = null;
-                }
-
-            }  
-         }
- 
-        final boolean isUserSet = 
-                origin == StyleOrigin.USER || origin == StyleOrigin.INLINE;
-
-        // now look for -fx-size, but don't look past the current node (hence 
-        // distance == 0 and negation of CONSIDER_INLINE_STYLES)        
-        CascadingStyle fontSize = lookupFontSubPropertyStyle(node, "-fx-font-size",
-                isUserSet, fontShorthand, 0, !CONSIDER_INLINE_STYLES);
-        
-        if (fontSize != null) {
-
-            final CalculatedValue cv = 
-                calculateValue(fontSize, node, dummyFontProperty, pseudoclassState, inlineStyles, 
-                    node, cacheEntry, null);
-            
-            if (cv.getValue() instanceof Double) {
-                if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {  
-                    origin = cv.getOrigin();
-                    foundSize = cv;
-                    foundShorthand = null;
-                    foundFont = null;
-                }
-             }
-
-         }
-         
-         
-        if (foundShorthand != null) {
-            
-            return foundShorthand;
-            
-        } else if (foundSize != null) {
-            
-            Font font = Font.font("system", ((Double)foundSize.getValue()).doubleValue());
-            return new CalculatedValue(font, foundSize.getOrigin(), foundSize.isRelative());
-            
-        } else if (foundFont != null) {
-         
-            // Did this found font come from a style? 
-            // If so, then the font used to convert it from a relative size
-            // (if conversion was needed) comes from the parent.
-            if (origin != null && origin != StyleOrigin.USER) {
-                
-                StyleCacheEntry parentCacheEntry = getParentCacheEntry(node);
-
-                if (parentCacheEntry != null && parentCacheEntry.getRelativeFont() != null) {
-                    isRelative = parentCacheEntry.getRelativeFont().isRelative();
-                } 
-            }
-            return new CalculatedValue(foundFont, origin, isRelative);
-            
-        } else {
-            
-            // no font, font-size or fontProp. 
-            // inherit by taking the parent's cache entry font.
-            StyleCacheEntry parentCacheEntry = getParentCacheEntry(node);
-            
-            if (parentCacheEntry != null && parentCacheEntry.getRelativeFont() != null) {
-                return parentCacheEntry.getRelativeFont();                    
-            } 
-        } 
-        // last ditch effort -  take the default font.
-        return new CalculatedValue(Font.getDefault(), null, false);
-     }
-
-    
-    private CascadingStyle lookupFontSubPropertyStyle(final Node node, 
-            final String subProperty, final boolean isUserSet,
-            final CascadingStyle csShorthand, 
-            final int distance,
-            boolean considerInlineStyles) {
-    
-        Node parent = node;
-        StyleHelper helper = this;
-        int nlooks = 0;
-        CascadingStyle returnValue = null;
-        StyleOrigin origin = null;
-        boolean consideringInline = false;
-        
-        while (parent != null && (consideringInline || nlooks <= distance)) {
-            
-            final long[] states = helper.getPseudoClassBits();
-            final Map<String,CascadingStyle> inlineStyles = StyleHelper.getInlineStyleMap(parent);
-            
-            CascadingStyle cascadingStyle = 
-                helper.getStyle(parent, subProperty, states, inlineStyles);
-            
-            if (isUserSet) {
-                //
-                // Don't look past this node if the user set the property.
-                //
-                if (cascadingStyle != null) {
-                    
-                    origin = cascadingStyle.getOrigin();
-
-                    // if the user set the property and the origin is the
-                    // user agent stylesheet, then we can't use the style
-                    // since ua styles shouldn't override user set values
-                    if (origin == StyleOrigin.USER_AGENT) {
-                        returnValue = null;
-                    }
-                }    
-                
-                break;
-                
-            } else if (cascadingStyle != null) {
-
-                //
-                // If isUserSet is false, then take the style if we found one.
-                // If csShorthand is not null, then were looking for an inline
-                // style. In this case, if the origin is INLINE, we'll take it.
-                // If it isn't INLINE we'll keep looking for an INLINE style.
-                //
-                final boolean isInline = cascadingStyle.getOrigin() == StyleOrigin.INLINE;
-                if (returnValue == null || isInline) {
-                    origin = cascadingStyle.getOrigin();
-                    returnValue = cascadingStyle;
-                    
-                    // If we found and inline style, then we don't need to look 
-                    // further. Also, if the style is not an inline style and we
-                    // don't want to consider inline styles, then look no further.
-                    if (isInline || considerInlineStyles == false) {
-                        
-                        break;
-                        
-                    } else {
-                        // 
-                        // If we are here, then the style is not an inline style
-                        // and we do want to consider inline styles. Setting
-                        // this flag will cause the code to look beyond nlooks
-                        // to see if there is an inline style
-                        //
-                        consideringInline = true;
-                    }
-                } 
-                
-            }
-                
-            // 
-            // haven't found it yet, or we're looking for an inline style
-            // so keep looking up the parent chain.
-            //
-            do {
-                parent = parent.getParent();
-                nlooks += 1;
-                helper = parent != null ? parent.impl_getStyleHelper() : null;
-            } while (parent != null && helper == null);
-        }
-        
-        if (csShorthand != null && returnValue != null) {
-       
-            final boolean shorthandImportant = 
-                    csShorthand.getStyle().getDeclaration().isImportant();
-            
-            final Style style = returnValue.getStyle();
-            final boolean returnValueIsImportant = 
-                style.getDeclaration().isImportant();
-
-            if (nlooks < distance) {
-                //
-                // if we found a font sub-property closer to the node than 
-                // the font shorthand, then the sub-property style
-                // wins provided the fontShorthand isn't important.
-                // If font shorthand is important and sub-property style is 
-                // important, then sub-property style wins (since, being closer
-                // to the node, it is more specific)
-                //                
-                if (shorthandImportant == true && returnValueIsImportant == false) {
-                    returnValue = null;
-                } 
-
-            } else if (csShorthand.compareTo(returnValue) < 0) {
-                //
-                // CascadingStyle.compareTo is such that a return value less
-                // than zero means the style is more specific than the arg.
-                // So if csShorthand is more specific than the return value,
-                // return null.
-                // 
-                // if we found font sub-property at the same distance from the
-                // node as the font shortand, then do a normal compare
-                // to see if the sub-property is more specific. If it isn't
-                // then return null.
-                //
-                returnValue = null;
-                        
-            }
-
-        }
-        
-        return returnValue;
-        
-    }
-    
-    /**
-     * Look up a font property. This is handled separately from lookup since
-     * font is inherited and has sub-properties. One should expect that the 
-     * text font for the following would be 16px Arial. The lookup method would
-     * give 16px system since it would look <em>only</em> for font-size, 
-     * font-family, etc <em>only</em> if the lookup on font failed.
-     * <pre>
-     * Text text = new Text("Hello World");
-     * text.setStyle("-fx-font-size: 16px;");
-     * Group group = new Group();
-     * group.setStyle("-fx-font: 12px Arial;");
-     * group.getChildren().add(text);
-     * </pre>
-     * @param node
-     * @param styleable
-     * @param isUserSet
-     * @param states
-     * @param userStyles
-     * @param originatingNode
-     * @param cacheEntry
-     * @param styleList
-     * @return 
-     */
-    private CalculatedValue lookupFont(Node node, CssMetaData styleable, 
-            boolean isUserSet, Node originatingNode, 
-            StyleCacheEntry cacheEntry, List<Style> styleList) {
-
-        // To make the code easier to read, define CONSIDER_INLINE_STYLES as true. 
-        // Passed to lookupFontSubProperty to tell it whether or not 
-        // it should look for inline styles
-        final boolean CONSIDER_INLINE_STYLES = true; 
-        
-        StyleOrigin origin = null;
-        boolean isRelative = false;
-            
-        // distance keeps track of how far up the parent chain we had to go
-        // to find a font shorthand. We'll look no further than this
-        // for the missing pieces. nlooks is used to keep track of how 
-        // many parents we've looked at. nlooks should never exceed distance. 
-        int distance = 0, nlooks = 0;
-        
-        Node parent = node;
-        StyleHelper helper = this;
-        String property = styleable == null ? null : styleable.getProperty();
-        CascadingStyle csShorthand = null;
-        while (parent != null) {
-            
-            final long[] states = helper.getPseudoClassBits();
-            final Map<String,CascadingStyle> inlineStyles = StyleHelper.getInlineStyleMap(parent);
-            
-            final CascadingStyle cascadingStyle =
-                helper.getStyle(parent, property, states, inlineStyles);
-            
-            if (isUserSet) {
-                //
-                // If isUserSet, then we don't look beyond the current node. 
-                // Only if the user did not set the font will we inherit.
-                //
-                if (cascadingStyle != null) {
-                
-                    origin = cascadingStyle.getOrigin();
-
-                    // if the user set font and the origin of the font shorthand
-                    // is the user agent stylesheet, then we can't use the style
-                    // since ua styles shouldn't override setFont
-                    if (origin != StyleOrigin.USER_AGENT) {
-                        csShorthand = cascadingStyle;
-                    }                    
-                }    
-                
-                break;
-                
-            } else if (cascadingStyle != null) {
-                //
-                // If isUserSet is false, then take the style if we found one.
-                // If csShorthand is not null, then were looking for an inline
-                // style. In this case, if the origin is INLINE, we'll take it.
-                // If it isn't INLINE we'll keep looking for an INLINE style.
-                //
-                final boolean isInline = cascadingStyle.getOrigin() == StyleOrigin.INLINE;
-                if (csShorthand == null || isInline) {
-                    origin = cascadingStyle.getOrigin();
-                    csShorthand = cascadingStyle;
-                    distance = nlooks;
-                    
-                    if (isInline) {
-                        break;
-                    }
-                } 
-                
-                
-            } 
-            
-            //
-            // If were here, then we either didn't find a style or we did find
-            // one but it wasn't inline. Either way, we need to keep looking
-            // up the parent chain for the next -fx-font.
-            //
-            do {
-                parent = parent.getParent();
-                nlooks += 1;
-                helper = parent != null ? parent.impl_getStyleHelper() : null;
-            } while (parent != null && helper == null);
-
-        }
-
-        if (csShorthand == null) {
-            distance = nlooks;
-        }
-        nlooks = 0;
-        
-        final long[] states = getPseudoClassBits();
-        final Map<String,CascadingStyle> inlineStyles = getInlineStyleMap(node);
-
-        String family = null;
-        double size = -1;
-        FontWeight weight = null;
-        FontPosture style = null;
-        
-        if (csShorthand != null) {
-            
-            if (styleList != null) {
-                styleList.add(csShorthand.getStyle());
-            }
-            
-            // pull out the pieces. 
-            final CalculatedValue cv = 
-                calculateValue(csShorthand, node, styleable, states, inlineStyles, 
-                    originatingNode, cacheEntry, styleList);
-            
-            // UA < AUTHOR < INLINE
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {
-                
-                if (cv.getValue() instanceof Font) {
-                    Font f = (Font)cv.getValue();
-                    isRelative = cv.isRelative();
-                    origin = cv.getOrigin();
-                
-                    // what did font shorthand specify? 
-                    ParsedValueImpl[] vals = 
-                            (ParsedValueImpl[])csShorthand.getParsedValueImpl().getValue();
-                    // Use family and size from converted font since the actual 
-                    // values may have been resolved. The weight and posture, 
-                    // however, are hard to get reliably from the font so use 
-                    // the parsed value instead. 
-                    if (vals[0] != null) family = f.getFamily();
-                    if (vals[1] != null) size   = f.getSize();
-                    if (vals[2] != null) weight = (FontWeight)vals[2].convert(null);
-                    if (vals[3] != null) style  = (FontPosture)vals[3].convert(null);
-
-                }
-            }
-            
-        }
-        
-        CascadingStyle csFamily = null; 
-        if ((csFamily = lookupFontSubPropertyStyle(node, property+"-family",
-                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES)) != null) {
-
-            if (styleList != null) {
-                styleList.add(csFamily.getStyle());
-            }
-            
-            final CalculatedValue cv = 
-                calculateValue(csFamily, node, styleable, states, inlineStyles, 
-                    originatingNode, cacheEntry, styleList);
-
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
-                if (cv.getValue() instanceof String) {
-                    family = Utils.stripQuotes((String)cv.getValue());
-                    origin = cv.getOrigin();
-                }
-            }
-                
-        }
-        
-        CascadingStyle csSize = null;
-        if ((csSize = lookupFontSubPropertyStyle(node, property+"-size",
-                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
-       
-            if (styleList != null) {
-                styleList.add(csSize.getStyle());
-            }
-
-            final CalculatedValue cv = 
-                calculateValue(csSize, node, styleable, states, inlineStyles, 
-                    originatingNode, cacheEntry, styleList);
-
-            // UA < AUTHOR < INLINE
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
-                if (cv.getValue() instanceof Double) {
-                    size = ((Double)cv.getValue()).doubleValue();
-                    isRelative = cv.isRelative();
-                    origin = cv.getOrigin();
-                }
-            }
-
-        }
-        
-        CascadingStyle csWeight = null;
-        if ((csWeight = lookupFontSubPropertyStyle(node, property+"-weight",
-                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
-
-            if (styleList != null) {
-                styleList.add(csWeight.getStyle());
-            }
-            
-            final CalculatedValue cv = 
-                calculateValue(csWeight, node, styleable, states, inlineStyles, 
-                    originatingNode, cacheEntry, styleList);
-
-            // UA < AUTHOR < INLINE
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
-                if (cv.getValue() instanceof FontWeight) {
-                    weight = (FontWeight)cv.getValue();
-                    origin = cv.getOrigin();
-                }
-            }
-                
-        }
-
-        CascadingStyle csStyle = null;
-        if ((csStyle = lookupFontSubPropertyStyle(node, property+"-style",
-                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
-            
-            if (styleList != null) {
-                styleList.add(csStyle.getStyle());
-            }
-            
-            final CalculatedValue cv = 
-                calculateValue(csStyle, node, styleable, states, inlineStyles, 
-                    originatingNode, cacheEntry, styleList);
-
-            // UA < AUTHOR < INLINE
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
-                if (cv.getValue() instanceof FontPosture) {
-                    style = (FontPosture)cv.getValue();
-                    origin = cv.getOrigin();
-                }
-            }                
-
-        }
-        
-        // if no styles were found, then skip...
-        if (family == null &&
-            size   == -1   &&
-            weight == null &&
-            style  == null) {
-            return SKIP;
-        }
-        
-        // Now we have all the pieces from the stylesheet
-        // still be some missing. We'll grab those from the node. 
-        StyleableProperty styleableProperty = styleable != null 
-                ? styleable.getStyleableProperty(node) 
-                : null;
-        Font f = null;
-        if (styleableProperty != null) {
-            f = (Font)styleableProperty.getValue();
-        }
-        if (f == null) f = Font.getDefault();
-
-        if (family == null) {
-            family = f.getFamily();
-        }
-
-        if (size == -1) {
-            size = f.getSize();                
-        }
-
-        Font val = null;
-        if (weight != null && style != null) {
-            val = Font.font(family, weight, style, size);            
-        } else if (weight != null) {
-            val = Font.font(family, weight, size);
-        } else if (style != null) {
-            val = Font.font(family, style, size);
-        } else {
-            val = Font.font(family, size);            
-        }
-
-        return new CalculatedValue(val, origin, isRelative);
-    }    
-    
-    /**
-     * Called from CssMetaData getMatchingStyles
-     * @param node
-     * @param styleableProperty
-     * @return 
-     */
-    public List<Style> getMatchingStyles(Styleable node, CssMetaData styleableProperty) {
-        
-        final List<CascadingStyle> styleList = new ArrayList<CascadingStyle>();
-
-        getMatchingStyles(node, styleableProperty, styleList);
-
-        List<CssMetaData<? extends Styleable, ?>> subProperties = styleableProperty.getSubProperties();
-        if (subProperties != null) {
-            for (int n=0,nMax=subProperties.size(); n<nMax; n++) {
-                final CssMetaData subProperty = subProperties.get(n);
-                getMatchingStyles(node, subProperty, styleList);                    
-            }
-        }
-
-        Collections.sort(styleList);
-
-        final List<Style> matchingStyles = new ArrayList<Style>(styleList.size());
-        for (int n=0,nMax=styleList.size(); n<nMax; n++) {
-            final Style style = styleList.get(n).getStyle();
-            if (!matchingStyles.contains(style)) matchingStyles.add(style);
-        }
-
-        return matchingStyles;
-    }
-    
-    private void getMatchingStyles(Styleable node, CssMetaData styleableProperty, List<CascadingStyle> styleList) {
-        
-        if (node != null) {
-            
-            Map<String,List<CascadingStyle>> inlineStyleMap = null;
-            
-            // create a map of inline styles.
-            Styleable parent = node;
-            while (parent != null) {
-                
-                StyleHelper parentHelper = (parent instanceof Node) ?
-                        ((Parent)parent).impl_getStyleHelper()
-                        : null;
-                
-                if (parentHelper != null) {
-                    
-                    Map<String,CascadingStyle> inlineStyles = StyleHelper.getInlineStyleMap(parent);
-                    
-                    if (inlineStyles != null) {
-                        
-                        if (inlineStyleMap == null) {
-                            inlineStyleMap = new HashMap<String,List<CascadingStyle>>();
-                        }
-                        
-                        for(Entry<String,CascadingStyle> entry : inlineStyles.entrySet()) {                            
-                            String kee = entry.getKey();
-                            
-                            List<CascadingStyle> inlineStyleList = inlineStyleMap.get(kee);
-                            if (inlineStyleList == null) {
-                                inlineStyleList = new ArrayList<CascadingStyle>();
-                                inlineStyleMap.put(kee, inlineStyleList);
-                            }
-                            inlineStyleList.add(entry.getValue());
-                        }
-                    }
-                }
-                parent = parent.getStyleableParent();
-            }
-                    
-            String property = styleableProperty.getProperty();
-            final Map<String, List<CascadingStyle>> smap = getStyleMap();
-            if (smap == null) return;
-            
-             List<CascadingStyle> styles = smap.get(property);            
-            
-//            if (inlineStyleMap != null) {
-//               if (inlineStyleMap.containsKey(property)) {
-//                    List<CascadingStyle> inlineStyleList = inlineStyleMap.get(property);
-//                    if (styles == null) styles = new ArrayList<CascadingStyle>();
-//                    styles.addAll(inlineStyleList);
-//                }
-//            }
-
-            if (styles != null) {
-                styleList.addAll(styles);
-                for (int n=0, nMax=styles.size(); n<nMax; n++) {
-                    final CascadingStyle style = styles.get(n);
-                    final ParsedValueImpl parsedValue = style.getParsedValueImpl();
-                    getMatchingLookupStyles(node, parsedValue, inlineStyleMap, styleList);
-                }
-            }
-            
-            if (styleableProperty.isInherits()) {
-                parent = node.getStyleableParent();
-                while (parent != null) {
-                    StyleHelper parentHelper = parent instanceof Node 
-                            ? ((Node)parent).impl_getStyleHelper()
-                            : null;
-                    if (parentHelper != null) {
-                        parentHelper.getMatchingStyles(parent, styleableProperty, styleList); 
-                    }
-                    parent = parent.getStyleableParent();
-                }
-            }
-            
-        }
-
-    }
-    
-    // Pretty much a duplicate of resolveLookups, but without the state
-    private void getMatchingLookupStyles(Styleable node, ParsedValueImpl parsedValue, Map<String,List<CascadingStyle>> inlineStyleMap, List<CascadingStyle> styleList) {
-                
-        if (parsedValue.isLookup()) {
-            
-            Object value = parsedValue.getValue();
-            
-            if (value instanceof String) {
-                
-                final String property = (String)value;
-                // gather up any and all styles that contain this value as a property
-                Styleable parent = node;
-                do {
-                    final StyleHelper helper = parent instanceof Node 
-                            ? ((Node)parent).impl_getStyleHelper()
-                            : null;
-                    if (helper != null) {
-                                             
-                        final int start = styleList.size();
-                        
-                        final Map<String, List<CascadingStyle>> smap = helper.getStyleMap();
-                        if (smap != null) {
-
-                            List<CascadingStyle> styles = smap.get(property);
-
-                            if (styles != null) {
-                                styleList.addAll(styles);
-                            }
-
-                        }
-                        
-                        List<CascadingStyle> inlineStyles = (inlineStyleMap != null) 
-                            ? inlineStyleMap.get(property) 
-                            : null;
-                        
-                        if (inlineStyles != null) {
-                            styleList.addAll(inlineStyles);
-                        }
-                        
-                        final int end = styleList.size();
-                        
-                        for (int index=start; index<end; index++) {
-                            final CascadingStyle style = styleList.get(index);
-                            getMatchingLookupStyles(parent, style.getParsedValueImpl(), inlineStyleMap, styleList);
-                        }
-                    }
-                                                                                    
-                } while ((parent = parent.getStyleableParent()) != null);
-            
-            }
-        }
-        
-        // If the value doesn't contain any values that need lookup, then bail
-        if (!parsedValue.isContainsLookups()) {
-            return;
-        }
-
-        final Object val = parsedValue.getValue();
-        if (val instanceof ParsedValueImpl[][]) {
-        // If ParsedValueImpl is a layered sequence of values, resolve the lookups for each.
-            final ParsedValueImpl[][] layers = (ParsedValueImpl[][])val;
-            for (int l=0; l<layers.length; l++) {
-                for (int ll=0; ll<layers[l].length; ll++) {
-                    if (layers[l][ll] == null) continue;
-                        getMatchingLookupStyles(node, layers[l][ll], inlineStyleMap, styleList);
-                }
-            }
-
-        } else if (val instanceof ParsedValueImpl[]) {
-        // If ParsedValueImpl is a sequence of values, resolve the lookups for each.
-            final ParsedValueImpl[] layer = (ParsedValueImpl[])val;
-            for (int l=0; l<layer.length; l++) {
-                if (layer[l] == null) continue;
-                    getMatchingLookupStyles(node, layer[l], inlineStyleMap, styleList);
-            }
-        }
-
-    }
-    
-}
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Fri Feb 22 15:41:59 2013 -0500
@@ -62,6 +62,7 @@
 import java.util.Map.Entry;
 import java.util.Set;
 import javafx.css.CssMetaData;
+import javafx.css.PseudoClass;
 import javafx.css.StyleOrigin;
 import sun.util.logging.PlatformLogger;
 
@@ -125,34 +126,7 @@
     public static StyleManager getInstance() {   
         return InstanceHolder.INSTANCE;
     }
-        
-    /**
-     * @return  The Styles that match this CSS property for the given Node. The 
-     * list is sorted by descending specificity. 
-     */
-    public static List<Style> getMatchingStyles(CssMetaData cssMetaData, Node node) {
-        if (node != null && cssMetaData != null) {
-            return getMatchingStyles(cssMetaData, node);
-        }
-        return Collections.<Style>emptyList();
-    }
-
-    /**
-     * @return  The Styles that match this CSS property for the given Styleable. The 
-     * list is sorted by descending specificity. 
-     */
-    public static List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable) {
-        if (styleable != null && cssMetaData != null) {
-            StyleHelper helper = styleable instanceof Node 
-                    ? ((Node)styleable).impl_getStyleHelper()
-                    : null;
-            return (helper != null) 
-                ? helper.getMatchingStyles(styleable, cssMetaData) 
-                : Collections.<Style>emptyList(); 
-        }
-        return Collections.<Style>emptyList();
-    }    
- 
+         
     /**
      * 
      * @param node
@@ -1099,13 +1073,13 @@
     }
     
     // reuse key to avoid creation of numerous small objects
-    private final Key key = new Key();
-    private final List<String> masterKey = new ArrayList<String>();
-    
+    private Key key = null;
+    private List<String> masterKey = null;        
+
     /**
      * Finds matching styles for this Node.
      */
-    StyleMap findMatchingStyles(Node node, long[][] pseudoclassBits) {
+    public StyleMap findMatchingStyles(Node node, Set<PseudoClass>[] triggerStates) {
         
         final Scene scene = node.getScene();
         if (scene == null) {
@@ -1136,65 +1110,69 @@
                 && userAgentStylesheets.isEmpty()) {
             return StyleMap.EMPTY_MAP;
         }
-                
-        if (hasSceneStylesheets) {
-            for (StylesheetContainer container : sceneStylesheets) {
+        
+        if (masterKey == null) {
+            masterKey = new ArrayList<String>();
+        }         
+
+        if (userAgentStylesheets.isEmpty() == false) {
+            for(int n=0, nMax=userAgentStylesheets.size(); n<nMax; n++) {
+                final StylesheetContainer container = userAgentStylesheets.get(n);
                 masterKey.add(container.fname);
-            };
-        }
-        if (hasParentStylesheets) {
-            for (StylesheetContainer container : parentStylesheets) {
-                masterKey.add(container.fname);
-            };
+            }
         }
         
-        Map<Key, Cache> cacheMap = masterCacheMap.get(
-                masterKey.isEmpty() ? null : masterKey
-        );
-                
+        if (hasSceneStylesheets) {
+            for(int n=0, nMax=sceneStylesheets.size(); n<nMax; n++) {
+                final StylesheetContainer container = sceneStylesheets.get(n);
+                masterKey.add(container.fname);
+            }
+        }
+        
+        if (hasParentStylesheets) {
+            for(int n=0, nMax=parentStylesheets.size(); n<nMax; n++) {
+                final StylesheetContainer container = parentStylesheets.get(n);
+                masterKey.add(container.fname);
+            }
+        }
+
+        assert(masterKey.isEmpty() == false);
+        Map<Key, Cache> cacheMap = masterCacheMap.get(masterKey);
+        
+        if (cacheMap != null) {
+            // masterKey is reused, so clear it for next use
+            masterKey.clear();
+        } else {
+            cacheMap = new HashMap<Key, Cache>();
+            masterCacheMap.put(masterKey, cacheMap);
+            masterKey = null;
+        }
+        
         final String name = node.getClass().getName();
         final int dotPos = name.lastIndexOf('.');
         final String cname = name.substring(dotPos+1);  // want Foo, not bada.bing.Foo
         final String id = node.getId();
-        final long[] styleClassBits = node.impl_getStyleHelper().getStyleClassBits();
+        final List<String> styleClasses = node.getStyleClass();
+
+        if (key == null) {
+            key = new Key();
+        }
         
         key.className = cname;
         key.id = id;
-        key.styleClass = styleClassBits;
+        for(int n=0, nMax=styleClasses.size(); n<nMax; n++) {
+            key.styleClasses.add(StyleClassSet.getStyleClass(styleClasses.get(n)));
+        }
 
-        Cache cache = cacheMap != null ? cacheMap.get(key) : null;
-        
-        if (cacheMap == null) {
-            
-            cacheMap = new HashMap<Key, Cache>();
-            
-            List<String> newMasterKey = null;
-            if (masterKey.isEmpty() == false) {
-                newMasterKey = new ArrayList<String>(masterKey);
-            } else {
-                newMasterKey = null;
-            }
-            
-            masterCacheMap.put(newMasterKey, cacheMap);
-        }
-        masterKey.clear();
-        
-        // 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 StyleHelper)
-        key.styleClass = null;
+        Cache cache = cacheMap.get(key);
+                
+        if (cache != null) {
+            // key will be reused, so clear the styleClasses for next use
+            key.styleClasses.clear();
+        } else {
 
-        // If the cache is null, then we need to create a new Cache and
-        // add it to the cache map
-        if (cache == null) {
-
-            final Key newKey = new Key();
-            newKey.className = cname;
-            newKey.id = id;
-            newKey.styleClass = 
-                styleClassBits != null 
-                    ? Arrays.copyOf(styleClassBits, styleClassBits.length) 
-                    : null;
+            // If the cache is null, then we need to create a new Cache and
+            // add it to the cache map
             
             // Construct the list of Rules that could possibly apply
             final List<Rule> rules = new ArrayList<Rule>();
@@ -1206,7 +1184,7 @@
                     
                     if (container != null && container.selectorPartitioning != null) {
                         final List<Rule> matchingRules = 
-                                container.selectorPartitioning.match(id, cname, styleClassBits);
+                                container.selectorPartitioning.match(id, cname, key.styleClasses);
                         rules.addAll(matchingRules);
                     }
                 }
@@ -1218,9 +1196,9 @@
                 for(int n=0, nMax=sceneStylesheets.size(); n<nMax; n++) {
                     final StylesheetContainer container = sceneStylesheets.get(n);
                     if (container != null && container.selectorPartitioning != null) {
-                        container.keys.add(newKey); // remember that this stylesheet was used in this cache
+                        container.keys.add(key); // remember that this stylesheet was used in this cache
                         final List<Rule> matchingRules = 
-                                container.selectorPartitioning.match(id, cname, styleClassBits);
+                                container.selectorPartitioning.match(id, cname, key.styleClasses);
                         rules.addAll(matchingRules);
                     }
                 }
@@ -1231,10 +1209,10 @@
                 final int nMax = parentStylesheets == null ? 0 : parentStylesheets.size();
                 for(int n=0; n<nMax; n++) {
                     final StylesheetContainer container = parentStylesheets.get(n);
-                    container.keys.add(newKey); // remember that this stylesheet was used in this cache
+                    container.keys.add(key); // remember that this stylesheet was used in this cache
                     if (container.selectorPartitioning != null) {
                         final List<Rule> matchingRules = 
-                                container.selectorPartitioning.match(id, cname, styleClassBits);
+                                container.selectorPartitioning.match(id, cname, key.styleClasses);
                         rules.addAll(matchingRules);
                     }
                 }
@@ -1242,14 +1220,16 @@
             
             // create a new Cache from these rules.
             cache = new Cache(rules);   
-            cacheMap.put(newKey, cache);
+            cacheMap.put(key, cache);
             
+            // cause a new Key to be created the next time this method is called
+            key = null;
         }
 
         //
         // Create a style helper for this node from the styles that match. 
         //
-        StyleMap smap = cache.getStyleMap(this, node, pseudoclassBits);
+        StyleMap smap = cache.getStyleMap(this, node, triggerStates);
         
         return smap;        
     }
@@ -1302,46 +1282,26 @@
     private int baseStyleMapId = 0;
 
     private int nextSmapId() {
-        return ++styleMapId;
+        styleMapId = baseStyleMapId + styleMapList.size();
+        return styleMapId;
     }
        
     private void addStyleMap(StyleMap smap) {
-        assert ((smap.id - baseStyleMapId - 1) == styleMapList.size());
+        assert ((smap.getId() - baseStyleMapId) == styleMapList.size());
         styleMapList.add(smap);
     }
     
-    StyleMap getStyleMap(int smapId) {
+    public StyleMap getStyleMap(int smapId) {
         
-        if (smapId == StyleMap.EMPTY_MAP.id) return StyleMap.EMPTY_MAP;
+        final int correctedId = smapId - baseStyleMapId;
         
-        final int smapCount = styleMapList.size();
-        final int correctedId = smapId - baseStyleMapId - 1;
-        
-        if (correctedId < 0 || smapCount <= correctedId) return null;
-        return styleMapList.get(correctedId);
-    }
-    
-    //
-    // Used by StyleHelper. The key uniquely identifies this style map.
-    // These keys are used by StyleHelper in creating its StyleCacheKey.
-    // The StyleCacheKey is used to lookup calculated values in cache.
-    //
-    static class StyleMap {
-        
-        private StyleMap(int id, Map<String, List<CascadingStyle>> map) {
-            this.id = id;
-            this.map  = map;
+        if (0 <= correctedId && correctedId < styleMapList.size()) {
+            return styleMapList.get(correctedId);
         }
         
-        static final StyleMap EMPTY_MAP = 
-            new StyleMap(0, Collections.<String,List<CascadingStyle>>emptyMap());
-
-        final int id; // unique per container
-        final Map<String, List<CascadingStyle>> map;
+        return StyleMap.EMPTY_MAP;
+    }
         
-    }
-
-    
     /**
      * Creates and caches maps of styles, reusing them as often as practical.
      */
@@ -1387,7 +1347,7 @@
             this.cache = new HashMap<Key, Integer>();
         }
 
-        private StyleMap getStyleMap(StyleManager owner, Node node, long[][] pseudoclassBits) {
+        private StyleMap getStyleMap(StyleManager owner, Node node, Set<PseudoClass>[] triggerStates) {
             
             if (rules == null || rules.isEmpty()) {                
                 return StyleMap.EMPTY_MAP;
@@ -1414,12 +1374,12 @@
                 final Rule rule = rules.get(r);
 
                 //
-                // 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. 
+                // This particular flavor of applies takes a PseudoClassState[]
+                // fills in the pseudo-class states from the selectors where 
+                // they apply to a node. This is an expedient to looking the
+                // applies loopa 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
@@ -1427,7 +1387,7 @@
                 // [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
+                // Note also that, if the rule does not apply, the triggerStates
                 // is unchanged. 
                 //
                 
@@ -1440,7 +1400,8 @@
                     count = 0;
                 }
                 
-                long mask = rule.applies(node, pseudoclassBits);
+                long mask = rule.applies(node, triggerStates);
+                
                 if (mask != 0) {
                     key[index] |= mask << count;
                     applicableRules[r] = rule;
@@ -1559,8 +1520,12 @@
         // necessary.
         String className;
         String id;
-        long[] styleClass;
+        final StyleClassSet styleClasses;
 
+        private Key() {
+            styleClasses = new StyleClassSet();
+        }
+        
         @Override
         public boolean equals(Object o) {
             if (this == o) {
@@ -1577,23 +1542,7 @@
                     return false;
                 }
 
-                if (styleClass == null ? other.styleClass != null : other.styleClass == null) {
-                    
-                    return false;
-                    
-                } else if (styleClass != null) {
-        
-                    if (styleClass.length != other.styleClass.length) {
-                        return false;
-                    }
-
-                    for (int n=0, max=styleClass.length; n<max; n++) {
-                        if (styleClass[n] != other.styleClass[n]) {
-                            return false;
-                        }
-                    }
-                    
-                }
+                return this.styleClasses.equals(other.styleClasses);
             }
             return true;
         }
@@ -1603,15 +1552,10 @@
             int hash = 7;
             hash = 29 * hash + (this.className != null ? this.className.hashCode() : 0);
             hash = 29 * hash + (this.id != null ? this.id.hashCode() : 0);
-            hash = 29 * hash + Arrays.hashCode(this.styleClass);
+            hash = 29 * hash + this.styleClasses.hashCode();
             return hash;
         }
 
-        @Override
-        public String toString() {
-            return "Key ["+className+", "+String.valueOf(id)+", "+String.valueOf(SimpleSelector.getStyleClassStrings(styleClass))+"]";
-        }
-
     }
     
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleMap.java	Fri Feb 22 15:41:59 2013 -0500
@@ -0,0 +1,56 @@
+/*
+ * 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.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A map of property name to the cascading styles that match a node.
+ */
+public final class StyleMap {
+
+    public static final StyleMap EMPTY_MAP = 
+        new StyleMap(-1, Collections.<String,List<CascadingStyle>>emptyMap());
+
+    /** Only StyleManager creates StyleMap */
+    StyleMap(int id, Map<String, List<CascadingStyle>> map) {
+        this.id = id;
+        this.map  = map;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public Map<String, List<CascadingStyle>> getMap() {
+        return map;
+    }
+        
+    private final int id; // unique per container
+    private final Map<String, List<CascadingStyle>> map;            
+}
--- a/javafx-ui-common/src/javafx/css/PseudoClass.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/javafx/css/PseudoClass.java	Fri Feb 22 15:41:59 2013 -0500
@@ -24,7 +24,7 @@
  */
 package javafx.css;
 
-import com.sun.javafx.css.PseudoClassImpl;
+import com.sun.javafx.css.PseudoClassState;
 
 /**
  * PseudoClass represents one unique pseudo-class state. Introducing a 
@@ -81,7 +81,7 @@
      */
     public static PseudoClass getPseudoClass(String pseudoClass) {
         
-        final PseudoClass instance = PseudoClassImpl.getPseudoClassImpl(pseudoClass);
+        final PseudoClass instance = PseudoClassState.getPseudoClass(pseudoClass);
         return instance;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/javafx/scene/CssStyleHelper.java	Fri Feb 22 15:41:59 2013 -0500
@@ -0,0 +1,2164 @@
+/*
+ * Copyright (c) 2011, 2013, 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;
+
+import com.sun.javafx.Logging;
+import com.sun.javafx.Utils;
+import com.sun.javafx.css.CalculatedValue;
+import static com.sun.javafx.css.CalculatedValue.SKIP;
+import com.sun.javafx.css.CascadingStyle;
+import com.sun.javafx.css.CssError;
+import com.sun.javafx.css.Declaration;
+import com.sun.javafx.css.ParsedValueImpl;
+import com.sun.javafx.css.PseudoClassState;
+import com.sun.javafx.css.Rule;
+import com.sun.javafx.css.Selector;
+import com.sun.javafx.css.Style;
+import com.sun.javafx.css.StyleCache;
+import com.sun.javafx.css.StyleCacheEntry;
+import com.sun.javafx.css.StyleConverterImpl;
+import com.sun.javafx.css.StyleManager;
+import com.sun.javafx.css.StyleMap;
+import com.sun.javafx.css.Stylesheet;
+import com.sun.javafx.css.converters.FontConverter;
+import com.sun.javafx.css.parser.CSSParser;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.collections.ObservableMap;
+import javafx.css.CssMetaData;
+import javafx.css.FontCssMetaData;
+import javafx.css.PseudoClass;
+import javafx.css.StyleConverter;
+import javafx.css.StyleOrigin;
+import javafx.css.Styleable;
+import javafx.css.StyleableProperty;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontPosture;
+import javafx.scene.text.FontWeight;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * The StyleHelper is a helper class used for applying CSS information to Nodes.
+ */
+final class CssStyleHelper {
+
+    private static final PlatformLogger LOGGER = com.sun.javafx.Logging.getCSSLogger();
+
+    private CssStyleHelper() {  
+        this.triggerStates = new PseudoClassState();
+    }
+    
+    /**
+     * Creates a new StyleHelper.
+     */
+    static CssStyleHelper createStyleHelper(Node node) {
+        
+        // need to know how far we are to root in order to init arrays.
+        // TODO: should we hang onto depth to avoid this nonsense later?
+        // TODO: is there some other way of knowing how far from the root a node is?
+        Node parent = node;
+        int depth = 0;
+        while(parent != null) {
+            depth++;
+            parent = parent.getParent();
+        }
+                
+        // The List<CacheEntry> should only contain entries for those
+        // pseudo-class states that have styles. The StyleHelper's
+        // pseudoclassStateMask is a bitmask of those pseudoclasses that
+        // appear in the node's StyleHelper's smap. This list of
+        // pseudo-class masks is held by the StyleCacheKey. When a node is
+        // styled, its pseudoclasses and the pseudoclasses of its parents
+        // are gotten. By comparing the actual pseudo-class state to the
+        // pseudo-class states that apply, a CacheEntry can be created or
+        // fetched using only those pseudoclasses that matter.
+        final PseudoClassState[] triggerStates = new PseudoClassState[depth];
+        
+        final StyleMap styleMap = 
+                StyleManager.getInstance().findMatchingStyles(node, triggerStates);
+
+        
+        final Map<String, List<CascadingStyle>> smap 
+                = styleMap != null ? styleMap.getMap() : null;
+        
+        if (smap == null || smap.isEmpty()) {
+            
+            // If there are no styles at all, and no styles that inherit, then return
+            final String inlineStyle = node.getStyle();
+            if (inlineStyle == null || inlineStyle.trim().isEmpty()) {
+                
+                boolean mightInherit = false;
+                final List<CssMetaData<? extends Styleable, ?>> props = node.getCssMetaData();
+                
+                final int pMax = props != null ? props.size() : 0;
+                for (int p=0; p<pMax; p++) {
+                    
+                    final CssMetaData<? extends Styleable, ?> prop = props.get(p);
+                    if (prop.isInherits()) {
+                        mightInherit = true;
+                        break;
+                    }
+                }
+                
+                if (mightInherit == false) {
+                    return null;
+                }
+            }
+        }   
+        
+        final CssStyleHelper helper = new CssStyleHelper();
+        
+        helper.triggerStates.addAll(triggerStates[0]);
+
+        // make sure parent's transition states include the pseudo-classes 
+        // found when matching selectors
+        parent = node.getParent();
+        for(int n=1; n<depth; n++) {
+
+            final PseudoClassState triggerState = triggerStates[n];
+
+            // if there is nothing in triggerState, then continue since there
+            // isn't any pseudo-class state that might trigger a state change
+            if (triggerState != null && triggerState.size() > 0) {
+
+                // Create a StyleHelper for the parent, if necessary. 
+                if (parent.styleHelper == null) {
+                    parent.styleHelper = new CssStyleHelper();
+                }
+                parent.styleHelper.triggerStates.addAll(triggerState);
+                
+            }   
+            
+            parent=parent.getParent();
+        }         
+        
+        helper.cacheMetaData = new CacheMetaData(node, styleMap, depth);
+        return helper;
+    }
+    
+    private CacheMetaData cacheMetaData;
+        
+    private final static class CacheMetaData {
+
+        // Set internal internalState structures
+        private CacheMetaData(
+                Node node, 
+                StyleMap styleMap, 
+                int depth) {
+
+            int ctr = 0;
+            int[] smapIds = new int[depth];
+            smapIds[ctr++] = this.smapId = styleMap.getId();
+            
+            //
+            // Create a set of StyleMap id's from the parent's smapIds.
+            // The resulting smapIds array may have less than depth elements.
+            // If a parent doesn't have a styleHelper or the styleHelper's
+            // internal state is null, then that parent doesn't contribute
+            // to the selection of a style. Any Node that has the same
+            // set of smapId's can potentially share previously calculated
+            // values.
+            //
+            Parent parent = node.getParent();
+            for(int d=1; d<depth; d++) {
+                
+                final CssStyleHelper helper = parent.styleHelper;
+                if (helper != null && helper.cacheMetaData != null) {                
+                    smapIds[ctr++] = helper.cacheMetaData.smapId;
+                }
+                parent = parent.getParent();
+                
+            }
+
+            this.styleCacheKey = new StyleCache.Key(smapIds, ctr);
+
+            this.localStyleCache = new StyleCache();
+                        
+            CssMetaData<Styleable,Font> styleableFontProperty = null;
+            
+            final List<CssMetaData<? extends Styleable, ?>> props = node.getCssMetaData();
+            final int pMax = props != null ? props.size() : 0;
+            for (int p=0; p<pMax; p++) {
+                final CssMetaData<? extends Styleable, ?> prop = props.get(p);
+            
+                if ("-fx-font".equals(prop.getProperty())) {
+                    // unchecked!
+                    styleableFontProperty = (CssMetaData<Styleable, Font>) prop;
+                    break;
+                }
+            }
+
+            this.fontProp = styleableFontProperty;
+        
+        }
+                
+        private final CssMetaData<Styleable,Font> fontProp;
+        private final int smapId;
+        private final StyleCache.Key styleCacheKey;
+        private final StyleCache localStyleCache;
+        
+    }
+    
+    //
+    // Find the entry in local cache and in the shared cache that matches the
+    // states. Whether or not this is a newly created StyleCacheEntry is returned
+    // in isNewEntry[0].
+    private StyleCacheEntry getStyleCacheEntry(Node node, boolean[] isNewEntry) {
+
+        if (cacheMetaData == null) return null;
+        
+        //
+        // StyleHelper#triggerStates is the set of pseudo-classes that appear
+        // in the style maps of this StyleHelper. Calculated values are
+        // cached by pseudo-class state, but only the pseudo-class states
+        // that mater are used in the search. So we take the transition states
+        // and intersect them with triggerStates to remove the
+        // transition states that don't matter when it comes to matching states
+        // on a  selector. For example if the style map contains only
+        // .foo:hover { -fx-fill: red; } then only the hover state matters
+        // but the transtion state could be [hover, focused]
+        //
+        
+        Set<PseudoClass>[] transitionStates = getTransitionStates(node);
+        
+        final Set<PseudoClass>[] pclassMask = new PseudoClassState[transitionStates.length];
+        
+        int count = 0;
+        int depth = 0;
+        Node parent = node;
+        while (parent != null) {
+            final CssStyleHelper helper = parent.styleHelper;
+            if (helper != null) {
+                pclassMask[count] = new PseudoClassState();
+                pclassMask[count].addAll(transitionStates[depth]);
+                pclassMask[count].retainAll(helper.triggerStates);
+                count += 1;
+            }
+            depth += 1;
+            parent = parent.getParent();
+        }
+
+        StyleCacheEntry.Key key = new StyleCacheEntry.Key(pclassMask, count);
+                
+        // find the entry in the list with the same pclassMask
+        StyleCacheEntry localCacheEntry = cacheMetaData.localStyleCache.getStyleCacheEntry(key);
+
+        if (localCacheEntry == null) {
+            
+            if (isNewEntry != null && isNewEntry.length > 0) {
+                isNewEntry[0] = true;
+            }
+            
+            Map<String,CascadingStyle> inlineStyles = getInlineStyleMap(node);
+            
+            localCacheEntry = new StyleCacheEntry(cacheMetaData.styleCacheKey, key);
+            
+            final CalculatedValue relativeFont = 
+                getFontForUseInConvertingRelativeSize(
+                    node, 
+                    localCacheEntry, 
+                    transitionStates[0], 
+                    inlineStyles
+                );            
+            
+            assert(relativeFont != null);
+            localCacheEntry.setFont(relativeFont);
+            
+            cacheMetaData.localStyleCache.putStyleCacheEntry(key, localCacheEntry);
+            
+        }
+        
+        return localCacheEntry;
+        
+    }
+    
+    void inlineStyleChanged(Node node) {
+
+        // Clear local cache so styles will be recalculated. 
+        // Since we're clearing the cache and getting (potentially) 
+        // new styles, reset the properties to initial values.
+        if (cacheMetaData != null) {
+            
+            node.impl_cssResetInitialValues();
+            cacheMetaData.localStyleCache.clear();
+            
+            // do we have any styles at all now?
+            final String inlineStyle = node.getStyle();
+            if(inlineStyle == null && inlineStyle.isEmpty()) {
+
+                final Map<String, List<CascadingStyle>> smap = getStyleMap();            
+                if (smap == null || smap.isEmpty()) {
+                    // We have no styles! Reset this StyleHelper to its
+                    // initial state so that calls to transitionToState 
+                    // become a no-op.
+                    cacheMetaData = null;
+                }
+                
+                // If smap isn't empty, then there are styles that
+                // apply to the node. There isn't a need to remap the styles
+                // since we've only removed an inline style and inline styles
+                // aren't part of the style map.
+            }
+
+            
+            
+            
+        } else {
+            final String inlineStyle = node.getStyle();
+            if (inlineStyle == null || inlineStyle.isEmpty()) {
+                return;
+            }
+            // if we don't have a localStyleCache, that means this 
+            // node doesn't have any applicable styles and it didn't
+            // have an inline style before. If it did have an inline
+            // style before, then there would be an smap, albeit an
+            // an empty one. See setStyles for this bit of logic. 
+            // But now the  node does have an inline style and so it
+            // needs to have an smap and localStyleCache for the logic
+            // in transitionToState to work. 
+            Node parent = node;
+            int depth = 0;
+            while(parent != null) {
+                depth++;
+                parent = parent.getParent();
+            }
+
+            cacheMetaData = new CacheMetaData(node, StyleMap.EMPTY_MAP, depth);
+        }
+        
+    }
+        
+    private Map<String, List<CascadingStyle>> getStyleMap() {
+        if (cacheMetaData == null) return null;
+        StyleMap styleMap = StyleManager.getInstance().getStyleMap(cacheMetaData.smapId);
+        return (styleMap != null) ? styleMap.getMap() : null;
+    }
+    
+    /**
+     * A convenient place for holding default values for populating the
+     * List&lt;Style&gt; that is populated if the Node has a 
+     * Map&lt;WritableValue&gt;, List&lt;Style&gt;. 
+     * See handleNoStyleFound
+     */
+    private static final Map<CssMetaData<? extends Styleable, ?>,Style> stylesFromDefaults = 
+            new HashMap<CssMetaData<? extends Styleable, ?>,Style>();
+    
+    /**
+     * The List to which Declarations fabricated from StyleablePropeerty 
+     * defaults are added.
+     */
+    private static final List<Declaration> declarationsFromDefaults;
+    
+    /**
+     * The Styles in defaultsStyles need to belong to a stylesheet. 
+     */
+    private static final Stylesheet defaultsStylesheet;
+    static {
+        final Rule defaultsRule = 
+            new Rule(new ArrayList<Selector>(), Collections.<Declaration>emptyList());
+        defaultsRule.getSelectors().add(Selector.getUniversalSelector());
+        declarationsFromDefaults = defaultsRule.getDeclarations();
+        defaultsStylesheet = new Stylesheet();
+        defaultsStylesheet.setOrigin(null);
+        defaultsStylesheet.getRules().add(defaultsRule);
+    };
+        
+    /** 
+     * Cache of parsed, inline styles. The key is Node.style. 
+     * The value is the set of property styles from parsing Node.style.
+     */
+    private static final Map<String,Map<String,CascadingStyle>> inlineStylesCache =
+        new HashMap<String,Map<String,CascadingStyle>>();
+
+    /**
+     * Get the map of property to style from the rules and declarations
+     * in the stylesheet. There is no need to do selector matching here since
+     * the stylesheet is from parsing Node.style.
+     */
+    private static Map<String,CascadingStyle> getInlineStyleMap(Stylesheet inlineStylesheet) {
+
+        final Map<String,CascadingStyle> inlineStyleMap = new HashMap<String,CascadingStyle>();
+        if (inlineStylesheet != null) {
+            // Order in which the declaration of a CascadingStyle appears (see below)
+            int ordinal = 0;
+            // For each declaration in the matching rules, create a CascadingStyle object
+            final List<Rule> stylesheetRules = inlineStylesheet.getRules();
+            for (int i = 0, imax = stylesheetRules.size(); i < imax; i++) {
+                final Rule rule = stylesheetRules.get(i);
+                final List<Declaration> declarations = rule.getDeclarations();
+                for (int k = 0, kmax = declarations.size(); k < kmax; k++) {
+                    Declaration decl = declarations.get(k);
+
+                    CascadingStyle s = new CascadingStyle(
+                        new Style(Selector.getUniversalSelector(), decl),
+                        NULL_PSEUDO_CLASS_STATE, // no pseudo classes
+                        0, // specificity is zero
+                        // 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++
+                    );
+
+                    inlineStyleMap.put(decl.getProperty(),s);
+                }
+            }
+        }
+        return inlineStyleMap;
+    }
+
+    /**
+     * Get the mapping of property to style from Node.style for this node.
+     */
+    private static Map<String,CascadingStyle> getInlineStyleMap(Styleable styleable) {
+        
+        final String inlineStyles = styleable.getStyle();
+
+        // If there are no styles for this property then we can just bail
+        if ((inlineStyles == null) || inlineStyles.isEmpty()) return null;
+
+        Map<String,CascadingStyle> styles = inlineStylesCache.get(inlineStyles);
+        
+        if (styles == null) {
+
+            Stylesheet inlineStylesheet =
+                CSSParser.getInstance().parseInlineStyle(styleable);
+            if (inlineStylesheet != null) {
+                inlineStylesheet.setOrigin(StyleOrigin.INLINE);
+            }
+            styles = getInlineStyleMap(inlineStylesheet);
+            
+            inlineStylesCache.put(inlineStyles, styles);
+        }
+
+        return styles;
+    }
+    
+    /**
+     * A Set of all the pseudo-class 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 pseudo-class state changes
+     * that are not in this hash set are ignored.
+     * *
+     * Called "triggerStates" since they would trigger a CSS update.
+     */
+    private PseudoClassState triggerStates = new PseudoClassState();
+    
+    boolean pseudoClassStateChanged(PseudoClass pseudoClass) {    
+        return triggerStates.contains(pseudoClass);
+    }    
+    
+    /**
+     * dynamic pseudo-class state of the node and its parents. 
+     * Only valid during a pulse. 
+     *
+     * The StyleCacheEntry to choose depends on the Node's state and
+     * the state of its parents. Without the parent state, the fact that
+     * the the node in this state matched foo:blah bar { } is lost.
+     *
+     */ 
+    private Set<PseudoClass>[] getTransitionStates(Node node) {
+
+        //
+        // Note Well: The array runs from leaf to root. That is, 
+        // transitionStates[0] is the pseudo-class state for node and 
+        // transitionStates[1..(states.length-1)] are the pseudoclassStates for the 
+        // node's parents.
+        //
+        
+        int count = 0;
+        Node parent = node;
+        while (parent != null) {
+            count += 1;
+            parent = parent.getParent();
+        }
+        
+        Set<PseudoClass>[] states = new PseudoClassState[count];
+        
+        count = 0;
+        parent = node;
+        while (parent != null) {
+            states[count] = parent.pseudoClassStates;
+            count += 1;
+            parent = parent.getParent();
+        }        
+        
+        return states;
+        
+    }
+    
+    ObservableMap<StyleableProperty<?>, List<Style>> observableStyleMap;
+     /**
+      * RT-17293
+      */
+     ObservableMap<StyleableProperty<?>, List<Style>> getObservableStyleMap() {
+         return observableStyleMap;
+     }
+
+     /**
+      * RT-17293
+      */
+     void setObservableStyleMap(ObservableMap<StyleableProperty<?>, List<Style>> observableStyleMap) {
+         this.observableStyleMap = observableStyleMap;
+     }
+          
+    
+    /**
+     * Called by the Node whenever it has transitioned from one set of
+     * pseudo-class states to another. This function will then lookup the
+     * new values for each of the styleable variables on the Node, 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.
+     */
+    void transitionToState(Node node) {
+       
+        if (cacheMetaData == null) {
+            return;
+        }
+        
+        //
+        // Styles that need lookup can be cached provided none of the styles
+        // are from Node.style.
+        //                
+        boolean[] isNewLocalCache = new boolean[] { false };
+        StyleCacheEntry cacheEntry = getStyleCacheEntry(node, isNewLocalCache);
+        
+        //
+        // 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 = 
+                CssStyleHelper.getInlineStyleMap(node);
+        
+        
+        final StyleOrigin relativeFontOrigin = 
+                cacheEntry.getFont() != null 
+                ? cacheEntry.getFont().getOrigin() 
+                : null;
+        //
+        //
+        boolean fastpath = 
+                // If the cacheEntry is new, 
+                //   then calculate styles for this set of states
+                isNewLocalCache[0] == false &&
+                // If someone is watching the styles, 
+                //   then we have to take the slow path.
+                observableStyleMap == null &&
+                // If this node has inline-styles, 
+                //   then we might not be able to use the value in shared cache.
+                inlineStyles == null &&
+                // If the relative font came from a user-set value, 
+                //   then we might not be able to use the value in shared cache.
+                relativeFontOrigin != StyleOrigin.USER && 
+                // If the relative font came from an inline-style, 
+                //   then we might not be able to use the value in shared cache.
+                relativeFontOrigin != StyleOrigin.INLINE;
+        
+        
+        final List<CssMetaData<? extends Styleable, ?>> styleables = node.getCssMetaData();
+        
+        // Used in the for loop below, and a convenient place to stop when debugging.
+        final int max = styleables.size();
+
+        // RT-20643
+        CssError.setCurrentScene(node.getScene());
+        
+        // For each property that is settable, we need to do a lookup and
+        // transition to that value.
+        for(int n=0; n<max; n++) {
+
+            @SuppressWarnings("unchecked") // this is a widening conversion
+            final CssMetaData<Styleable,Object> cssMetaData = 
+                    (CssMetaData<Styleable,Object>)styleables.get(n);
+            
+            if (observableStyleMap != null) {
+                StyleableProperty<?> styleableProperty = cssMetaData.getStyleableProperty(node);
+                if (styleableProperty != null && observableStyleMap.containsKey(styleableProperty)) {
+                    observableStyleMap.remove(styleableProperty);
+                }
+            }
+            
+
+            // Skip the lookup if we know there isn't a chance for this property
+            // to be set (usually due to a "bind").
+            if (!cssMetaData.isSettable(node)) continue;
+
+            final String property = cssMetaData.getProperty();
+            
+            // Create a List to hold the Styles if the node has 
+            // a Map<WritableValue, List<Style>>
+            final List<Style> styleList = (observableStyleMap != null) 
+                    ? new ArrayList<Style>() 
+                    : null;
+
+            CalculatedValue calculatedValue = null;
+            if (fastpath) {
+
+                calculatedValue = cacheEntry.get(property);
+                if (calculatedValue == null) continue;
+
+            }
+
+            if (calculatedValue == null) {
+
+                boolean isUserSet = isUserSetProperty(node, cssMetaData);            
+
+                calculatedValue = lookup(node, cssMetaData, isUserSet, node.pseudoClassStates, 
+                        inlineStyles, node, cacheEntry, styleList);
+
+            }
+            
+            // RT-10522:
+            // If the user set the property and there is a style and
+            // the style came from the user agent stylesheet, then
+            // skip the value. A style from a user agent stylesheet should
+            // not override the user set style.
+            //
+            // RT-21894: the origin might be null if the calculatedValue 
+            // comes from reverting back to the initial value. In this case,
+            // make sure the initial value doesn't overwrite the user set value.
+            // Also moved this condition from the fastpath block to here since
+            // the check needs to be done on any calculated value, not just
+            // calculatedValues from cache
+            //
+            if (calculatedValue == SKIP
+                || (   calculatedValue != null
+                    && (   calculatedValue.getOrigin() == StyleOrigin.USER_AGENT
+                        || calculatedValue.getOrigin() == null) 
+                    && isUserSetProperty(node, cssMetaData)
+                    )
+                ) {
+                continue;
+            }
+            
+                final Object value = calculatedValue.getValue();
+                if (LOGGER.isLoggable(PlatformLogger.FINER)) {
+                    LOGGER.finer("call " + node + ".impl_cssSet(" +
+                                    property + ", " + value + ")");
+                }
+
+                try {
+                    cssMetaData.set(node, value, calculatedValue.getOrigin());
+                    
+                    cacheEntry.put(property, calculatedValue);
+
+                    
+                    if (observableStyleMap != null) {
+                        StyleableProperty<?> styleableProperty = cssMetaData.getStyleableProperty(node);                            
+                        observableStyleMap.put(styleableProperty, styleList);
+                    }
+                    
+                } catch (Exception e) {
+
+                    // RT-27155: if setting value raises exception, reset value 
+                    // the value to initial and thereafter skip setting the property
+                    cssMetaData.set(node, cssMetaData.getInitialValue(node), null);
+                    cacheEntry.put(property, SKIP);
+                    
+                    List<CssError> errors = null;
+                    if ((errors = StyleManager.getErrors()) != null) {
+                        final String msg = String.format("Failed to set css [%s] due to %s\n", cssMetaData, e.getMessage());
+                        final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
+                        errors.add(error);
+                    }
+                    // TODO: use logger here
+                    PlatformLogger logger = Logging.getCSSLogger();
+                    if (logger.isLoggable(PlatformLogger.WARNING)) {
+                        logger.warning(String.format("Failed to set css [%s]\n", cssMetaData), e);
+                    }
+                }
+
+            }
+        
+        // RT-20643
+        CssError.setCurrentScene(null);
+
+        // If the list weren't empty, we'd worry about animations at this
+        // point. TODO need to implement animation trickery here
+    }
+
+    /**
+     * Gets the CSS CascadingStyle for the property of this node in these pseudo-class
+     * states. A null style may be returned if there is no style information
+     * for this combination of input parameters.
+     *
+     * @param node 
+     * @param property
+     * @param states
+     * @return
+     */
+    private CascadingStyle getStyle(Node node, String property, Set<PseudoClass> states, Map<String,CascadingStyle> inlineStyles){
+
+        assert node != null && property != null: String.valueOf(node) + ", " + String.valueOf(property);
+
+        final CascadingStyle inlineStyle = (inlineStyles != null) ? inlineStyles.get(property) : null;
+
+        // Get all of the Styles which may apply to this particular property
+        final Map<String, List<CascadingStyle>> smap = getStyleMap();
+        if (smap == null) return inlineStyle;
+
+        final List<CascadingStyle> styles = smap.get(property);
+
+        // If there are no styles for this property then we can just bail
+        if ((styles == null) || styles.isEmpty()) return inlineStyle;
+
+        // Go looking for the style. We do this by visiting each CascadingStyle in
+        // order finding the first that matches the current node & set of
+        // pseudo-class states. We use an iteration style that avoids creating
+        // garbage iterators (and wish javac did it for us...)
+       CascadingStyle style = null;
+        final int max = (styles == null) ? 0 : styles.size();
+        for (int i=0; i<max; i++) {
+            final CascadingStyle s = styles.get(i);
+            final Selector sel = s == null ? null : s.getSelector();
+            if (sel == null) continue; // bail if the selector is null.
+//System.out.println(node.toString() + "\n\tstates=" + PseudoClassSet.getPseudoClasses(states) + "\n\tstateMatches? " + sel.stateMatches(node, states) + "\n\tsel=" + sel.toString());            
+            if (sel.stateMatches(node, states)) {
+                style = s;
+                break;
+            }
+        }
+        
+        if (inlineStyle != null) {
+
+            // is inlineStyle more specific than style?    
+            if (style == null || inlineStyle.compareTo(style) < 0) {
+                style = inlineStyle;
+            }
+
+        }
+        return style;
+    }
+
+    /**
+     * The main workhorse of this class, the lookup method walks up the CSS
+     * style tree looking for the style information for the Node, the
+     * property associated with the given styleable, in these states for this font.
+     *
+     * @param node
+     * @param styleable
+     * @param states
+     * @param font
+     * @return
+     */
+    private CalculatedValue lookup(Node node, CssMetaData styleable, 
+            boolean isUserSet, Set<PseudoClass> states,
+            Map<String,CascadingStyle> userStyles, Node originatingNode, 
+            StyleCacheEntry cacheEntry, List<Style> styleList) {
+
+        if (styleable.getConverter() == FontConverter.getInstance()) {
+        
+            return lookupFont(node, styleable, isUserSet, 
+                    originatingNode, cacheEntry, styleList);
+        }
+        
+        final String property = styleable.getProperty();
+
+        // Get the CascadingStyle which may apply to this particular property
+        CascadingStyle style = getStyle(node, property, states, userStyles);
+
+        // If no style was found and there are no sub styleables, then there
+        // are no matching styles for this property. We will then either SKIP
+        // or we will INHERIT. We will inspect the default value for the styleable,
+        // and if it is INHERIT then we will inherit otherwise we just skip it.
+        final List<CssMetaData<? extends Styleable, ?>> subProperties = styleable.getSubProperties();
+        final int numSubProperties = (subProperties != null) ? subProperties.size() : 0;
+        if (style == null) {
+            
+            if (numSubProperties == 0) {
+                
+                return handleNoStyleFound(node, styleable, isUserSet, userStyles, 
+                        originatingNode, cacheEntry, styleList);
+                
+            } else {
+
+                // If style is null then it means we didn't successfully find the
+                // property we were looking for. However, there might be sub styleables,
+                // in which case we should perform a lookup for them. For example,
+                // there might not be a style for "font", but there might be one
+                // for "font-size" or "font-weight". So if the style is null, then
+                // we need to check with the sub-styleables.
+
+                // Build up a list of all SubProperties which have a constituent part.
+                // I default the array to be the size of the number of total
+                // sub styleables to avoid having the array grow.
+                Map<CssMetaData,Object> subs = null;
+                StyleOrigin origin = null;
+                
+                boolean isRelative = false;
+                
+                for (int i=0; i<numSubProperties; i++) {
+                    CssMetaData subkey = subProperties.get(i);
+                    CalculatedValue constituent = 
+                        lookup(node, subkey, isUserSet, states, userStyles, 
+                            originatingNode, cacheEntry, styleList);
+                    if (constituent != SKIP) {
+                        if (subs == null) {
+                            subs = new HashMap<CssMetaData,Object>();
+                        }
+                        subs.put(subkey, constituent.getValue());
+
+                        // origin of this style is the most specific
+                        if ((origin != null && constituent.getOrigin() != null)
+                                ? origin.compareTo(constituent.getOrigin()) < 0
+                                : constituent.getOrigin() != null) {
+                            origin = constituent.getOrigin();
+                        }
+                        
+                        // if the constiuent uses relative sizes, then 
+                        // isRelative is true;
+                        isRelative = isRelative || constituent.isRelative();
+                            
+                    }
+                }
+
+                // If there are no subkeys which apply...
+                if (subs == null || subs.isEmpty()) {
+                    return handleNoStyleFound(node, styleable, isUserSet, userStyles, 
+                            originatingNode, cacheEntry, styleList);
+                }
+
+                try {
+                    final StyleConverter keyType = styleable.getConverter();
+                    assert(keyType instanceof StyleConverterImpl);
+                    if (keyType instanceof StyleConverterImpl) {
+                        Object ret = ((StyleConverterImpl)keyType).convert(subs);
+                        return new CalculatedValue(ret, origin, isRelative);
+                    } else {
+                        return SKIP;
+                    }
+                } catch (ClassCastException cce) {
+                    final String msg = formatExceptionMessage(node, styleable, null, cce);
+                    List<CssError> errors = null;
+                    if ((errors = StyleManager.getErrors()) != null) {
+                        final CssError error = new CssError.PropertySetError(styleable, node, msg);
+                        errors.add(error);
+                    }
+                    if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
+                        LOGGER.warning("caught: ", cce);
+                        LOGGER.warning("styleable = " + styleable);
+                        LOGGER.warning("node = " + node.toString());
+                    }
+                    return SKIP;
+                }
+            }                
+            
+        } else { // style != null
+
+            // RT-10522:
+            // If the user set the property and there is a style and
+            // the style came from the user agent stylesheet, then
+            // skip the value. A style from a user agent stylesheet should
+            // not override the user set style.
+            if (isUserSet && style.getOrigin() == StyleOrigin.USER_AGENT) {
+                return SKIP;
+            }
+
+            // If there was a style found, then we want to check whether the
+            // value was "inherit". If so, then we will simply inherit.
+            final ParsedValueImpl cssValue = style.getParsedValueImpl();
+            if (cssValue != null && "inherit".equals(cssValue.getValue())) {
+                if (styleList != null) styleList.add(style.getStyle());
+                return inherit(node, styleable, userStyles, 
+                        originatingNode, cacheEntry, styleList);
+            }
+        }
+
+//        System.out.println("lookup " + property +
+//                ", selector = \'" + style.selector.toString() + "\'" +
+//                ", node = " + node.toString());
+
+        if (styleList != null) { 
+            styleList.add(style.getStyle());
+        }
+        
+        return calculateValue(style, node, styleable, states, userStyles, 
+                    originatingNode, cacheEntry, styleList);
+    }
+    
+    /**
+     * Called when there is no style found.
+     */
+    private CalculatedValue handleNoStyleFound(Node node, CssMetaData styleable,
+            boolean isUserSet, Map<String,CascadingStyle> userStyles, 
+            Node originatingNode, StyleCacheEntry cacheEntry, List<Style> styleList) {
+
+        if (styleable.isInherits()) {
+
+
+            // RT-16308: if there is no matching style and the user set 
+            // the property, do not look for inherited styles.
+            if (isUserSet) {
+
+                    return SKIP;
+                    
+            }
+
+            CalculatedValue cv =
+                inherit(node, styleable, userStyles, 
+                    originatingNode, cacheEntry, styleList);
+
+            return cv;
+
+        } else if (isUserSet) {
+
+            // Not inherited. There is no style but we don't want to
+            // set the default value if the user set the property
+            return SKIP;
+
+        } else {
+            
+            final Map<String, List<CascadingStyle>> smap = getStyleMap();
+            if (smap == null) return SKIP;
+            
+            if (smap.containsKey(styleable.getProperty())) {
+
+                // If there is a style in the stylemap but it just doen't apply,
+                // then it may have been set and it needs to be reset to its
+                // default value. For example, if there is a style for the hover
+                // pseudo-class state, but no style for the default state.
+                Object initialValue = styleable.getInitialValue(node);
+
+                if (styleList != null) {
+
+                    Style initialStyle = stylesFromDefaults.get(styleable);
+                    if (initialStyle != null) {
+                        if (!declarationsFromDefaults.contains(initialStyle.getDeclaration())) {
+                            declarationsFromDefaults.add(initialStyle.getDeclaration());
+                        }
+                    } else {
+                        initialStyle = new Style( 
+                            Selector.getUniversalSelector(),
+                            new Declaration(styleable.getProperty(), 
+                                        new ParsedValueImpl(initialValue, null), false));
+                        stylesFromDefaults.put(styleable, initialStyle);
+                        declarationsFromDefaults.add(initialStyle.getDeclaration());
+                    }
+
+                    styleList.add(initialStyle);
+                }
+
+                return new CalculatedValue(initialValue, null, false);
+
+            } else {
+
+                return SKIP;
+
+            }
+        }
+    }
+    /**
+     * Called when we must inherit a value from a parent node in the scenegraph.
+     */
+    private CalculatedValue inherit(Node node, CssMetaData styleable,
+            Map<String,CascadingStyle> userStyles, 
+            Node originatingNode, StyleCacheEntry cacheEntry, List<Style> styleList) {
+        
+        // Locate the first parentStyleHelper in the hierarchy
+        Node parent = node.getParent();        
+        CssStyleHelper parentStyleHelper = parent == null ? null : parent.styleHelper;
+        while (parent != null && parentStyleHelper == null) {
+            parent = parent.getParent();
+            if (parent != null) {
+                parentStyleHelper = parent.styleHelper;
+            }
+        }
+
+        if (parent == null) {
+            return SKIP;
+        }
+        return parentStyleHelper.lookup(parent, styleable, false,
+                parent.pseudoClassStates,
+                getInlineStyleMap(parent), originatingNode, cacheEntry, styleList);
+    }
+
+
+    // helps with self-documenting the code
+    static final Set<PseudoClass> NULL_PSEUDO_CLASS_STATE = null;
+    
+    /**
+     * Find the property among the styles that pertain to the Node
+     */
+    private CascadingStyle resolveRef(Node node, String property, Set<PseudoClass> states,
+            Map<String,CascadingStyle> inlineStyles) {
+        
+        final CascadingStyle style = getStyle(node, property, states, inlineStyles);
+        if (style != null) {
+            return style;
+        } else {
+            // if style is null, it may be because there isn't a style for this
+            // node in this state, or we may need to look up the parent chain
+            if (states != null && states.size() > 0) {
+                // if states > 0, then we need to check this node again,
+                // but without any states.
+                return resolveRef(node,property,NULL_PSEUDO_CLASS_STATE,inlineStyles);
+            } else {
+                // TODO: This block was copied from inherit. Both should use same code somehow.
+                Node parent = node.getParent();
+                CssStyleHelper parentStyleHelper = parent == null ? null : parent.styleHelper;
+                while (parent != null && parentStyleHelper == null) {
+                    parent = parent.getParent();
+                    if (parent != null) {
+                        parentStyleHelper = parent.styleHelper;
+                    }
+                }
+
+                if (parent == null || parentStyleHelper == null) {
+                    return null;
+                }
+                return parentStyleHelper.resolveRef(parent, property,
+                        parent.pseudoClassStates,
+                        getInlineStyleMap(parent));
+            }
+        }
+    }
+
+    // to resolve a lookup, we just need to find the parsed value.
+    private ParsedValueImpl resolveLookups(
+            Node node, 
+            ParsedValueImpl value, 
+            Set<PseudoClass> states,
+            Map<String,CascadingStyle> inlineStyles,
+            ObjectProperty<StyleOrigin> whence,
+            List<Style> styleList) {
+        
+        
+        assert(value instanceof ParsedValueImpl);
+        if ((value instanceof ParsedValueImpl) == false) { return value; }
+        
+        ParsedValueImpl parsedValue = (ParsedValueImpl)value;
+        
+        //
+        // either the value itself is a lookup, or the value contain a lookup
+        //
+        if (parsedValue.isLookup()) {
+
+            // The value we're looking for should be a Paint, one of the
+            // containers for linear, radial or ladder, or a derived color.
+            final Object val = parsedValue.getValue();
+            if (val instanceof String) {
+
+                final String sval = (String)val;
+                
+                CascadingStyle resolved = 
+                    resolveRef(node, sval, states, inlineStyles);
+
+                if (resolved != null) {
+                    
+                    if (styleList != null) {
+                        final Style style = resolved.getStyle();
+                        if (style != null && !styleList.contains(style)) {
+                            styleList.add(style);
+                        }
+                    }
+                    
+                    // The origin of this parsed value is the greatest of 
+                    // any of the resolved reference. If a resolved reference
+                    // comes from an inline style, for example, then the value
+                    // calculated from the resolved lookup should have inline
+                    // as its origin. Otherwise, an inline style could be 
+                    // stored in shared cache.
+                    final StyleOrigin wOrigin = whence.get();
+                    final StyleOrigin rOrigin = resolved.getOrigin();
+                    if (rOrigin != null && (wOrigin == null ||  wOrigin.compareTo(rOrigin) < 0)) {
+                        whence.set(rOrigin);
+                    } 
+                    
+                    // the resolved value may itself need to be resolved.
+                    // For example, if the value "color" resolves to "base",
+                    // then "base" will need to be resolved as well.
+                    return resolveLookups(node, resolved.getParsedValueImpl(), states, inlineStyles, whence, styleList);
+                }
+            }
+        }
+
+        // If the value doesn't contain any values that need lookup, then bail
+        if (!parsedValue.isContainsLookups()) {
+            return parsedValue;
+        }
+
+        final Object val = parsedValue.getValue();
+        if (val instanceof ParsedValueImpl[][]) {
+        // If ParsedValueImpl is a layered sequence of values, resolve the lookups for each.
+            final ParsedValueImpl[][] layers = (ParsedValueImpl[][])val;
+            for (int l=0; l<layers.length; l++) {
+                for (int ll=0; ll<layers[l].length; ll++) {
+                    if (layers[l][ll] == null) continue;
+                    layers[l][ll].setResolved(
+                        resolveLookups(node, layers[l][ll], states, inlineStyles, whence, styleList)
+                    );
+                }
+            }
+
+        } else if (val instanceof ParsedValueImpl[]) {
+        // If ParsedValueImpl is a sequence of values, resolve the lookups for each.
+            final ParsedValueImpl[] layer = (ParsedValueImpl[])val;
+            for (int l=0; l<layer.length; l++) {
+                if (layer[l] == null) continue;
+                layer[l].setResolved(
+                    resolveLookups(node, layer[l], states, inlineStyles, whence, styleList)
+                );
+            }
+        }
+
+        return parsedValue;
+
+    }
+    
+    private String getUnresolvedLookup(ParsedValueImpl resolved) {
+
+        Object value = resolved.getValue();
+
+        if (resolved.isLookup() && value instanceof String) {
+            return (String)value;
+        } 
+
+        if (value instanceof ParsedValueImpl[][]) {
+            final ParsedValueImpl[][] layers = (ParsedValueImpl[][])value;
+            for (int l=0; l<layers.length; l++) {
+                for (int ll=0; ll<layers[l].length; ll++) {
+                    if (layers[l][ll] == null) continue;
+                    String unresolvedLookup = getUnresolvedLookup(layers[l][ll]);
+                    if (unresolvedLookup != null) return unresolvedLookup;
+                }
+            }
+
+        } else if (value instanceof ParsedValueImpl[]) {
+        // If ParsedValueImpl is a sequence of values, resolve the lookups for each.
+            final ParsedValueImpl[] layer = (ParsedValueImpl[])value;
+            for (int l=0; l<layer.length; l++) {
+                if (layer[l] == null) continue;
+                String unresolvedLookup = getUnresolvedLookup(layer[l]);
+                if (unresolvedLookup != null) return unresolvedLookup;
+            }
+        }        
+        
+        return null;
+    }
+    
+    private String formatUnresolvedLookupMessage(Node node, CssMetaData styleable, Style style, ParsedValueImpl resolved) {
+        
+        // find value that could not be looked up
+        String missingLookup = resolved != null ? getUnresolvedLookup(resolved) : null;
+        if (missingLookup == null) missingLookup = "a lookup value";
+        
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("Could not resolve '")
+            .append(missingLookup)
+            .append("'")
+            .append(" while resolving lookups for '")
+            .append(styleable.getProperty())
+            .append("'");
+        
+        final Rule rule = style != null ? style.getDeclaration().getRule(): null;
+        final Stylesheet stylesheet = rule != null ? rule.getStylesheet() : null;
+        final java.net.URL url = stylesheet != null ? stylesheet.getUrl() : null;
+        if (url != null) {
+            sbuf.append(" from rule '")
+                .append(style.getSelector())
+                .append("' in stylesheet ").append(url.toExternalForm());
+        } else if (stylesheet != null && StyleOrigin.INLINE == stylesheet.getOrigin()) {
+            sbuf.append(" from inline style on " )
+                .append(node.toString());            
+        }
+        
+        return sbuf.toString();
+    }
+
+    private String formatExceptionMessage(Node node, CssMetaData styleable, Style style, Exception e) {
+        
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("Caught ")
+            .append(e.toString())
+            .append("'")
+            .append(" while calculating value for '")
+            .append(styleable.getProperty())
+            .append("'");
+        
+        final Rule rule = style != null ? style.getDeclaration().getRule(): null;
+        final Stylesheet stylesheet = rule != null ? rule.getStylesheet() : null;
+        final java.net.URL url = stylesheet != null ? stylesheet.getUrl() : null;
+        if (url != null) {
+            sbuf.append(" from rule '")
+                .append(style.getSelector())
+                .append("' in stylesheet ").append(url.toExternalForm());
+        } else if (stylesheet != null && StyleOrigin.INLINE == stylesheet.getOrigin()) {
+            sbuf.append(" from inline style on " )
+                .append(node.toString());            
+        }
+        
+        return sbuf.toString();
+    }
+    
+    
+    private CalculatedValue calculateValue(
+            final CascadingStyle style, 
+            final Node node, 
+            final CssMetaData cssMetaData, 
+            final Set<PseudoClass> states,
+            final Map<String,CascadingStyle> inlineStyles, 
+            final Node originatingNode, 
+            final StyleCacheEntry cacheEntry, 
+            final List<Style> styleList) {
+
+        final ParsedValueImpl cssValue = style.getParsedValueImpl();
+        if (cssValue != null && !("null").equals(cssValue.getValue())) {
+
+            ObjectProperty<StyleOrigin> whence = new SimpleObjectProperty<StyleOrigin>(style.getOrigin());
+            final ParsedValueImpl resolved = 
+                resolveLookups(node, cssValue, states, inlineStyles, whence, styleList);
+            
+            try {
+                // The computed value
+                Object val = null;
+                CalculatedValue fontValue = null;
+
+                //
+                // Avoid using a font calculated from a relative size
+                // to calculate a font with a relative size. 
+                // For example:
+                // Assume the default font size is 13 and we have a style with
+                // -fx-font-size: 1.5em, then the cacheEntry font value will 
+                // have a size of 13*1.5=19.5. 
+                // Now, when converting that same font size again in response
+                // to looking up a value for -fx-font, we do not want to use
+                // 19.5 as the font for relative size conversion since this will
+                // yield a font 19.5*1.5=29.25 when really what we want is
+                // a font size of 19.5.
+                // In this situation, then, we use the font from the parent's
+                // cache entry.
+                final String property = cssMetaData.getProperty();
+                if (resolved.isNeedsFont() &&
+                    (cacheEntry.getFont() == null || cacheEntry.getFont().isRelative()) &&
+                    ("-fx-font".equals(property) ||
+                     "-fx-font-size".equals(property)))  {
+                    
+                    Node parent = node;
+                    CalculatedValue cachedFont = cacheEntry.getFont();
+                    while(parent != null) {
+                        
+                        final StyleCacheEntry parentCacheEntry = 
+                            getParentCacheEntry(parent);
+                        
+                        if (parentCacheEntry != null) {
+                            fontValue = parentCacheEntry.getFont();
+                        
+                            if (fontValue != null && fontValue.isRelative()) {
+
+                                // If cacheEntry.font is null, then we're here by 
+                                // way of getFontForUseInConvertingRelativeSize
+                                // If  the fontValue is not relative, then the
+                                // cacheEntry.font needs to be calculated. If
+                                // fontValue is relative, then we can use it as
+                                // is - this is a hack for Control and SkinBase
+                                // which share the same styles (hence the check
+                                // for parent == node).
+                                // TBD - should check that they are the same styles
+    //                                if (parent == node && childCacheEntry.font == null) {
+    //                                    return fontValue;
+    //                                } 
+
+                                if (cachedFont != null) {
+                                    final Font ceFont = (Font)cachedFont.getValue();
+                                    final Font fvFont = (Font)fontValue.getValue();
+                                    if (ceFont.getSize() != fvFont.getSize()) {
+                                        // if the font sizes don't match, then
+                                        // the fonts came from distinct styles,
+                                        // otherwise, we need another level of
+                                        // indirection
+                                        break;
+                                    }
+                                } 
+
+                                // cachedFont is null or the sizes match
+                                // (implies the fonts came from the same style)
+                                cachedFont = fontValue;
+
+                            } else if (fontValue != null) {
+                                // fontValue.isRelative() == false
+                                break;
+                            }
+                        }
+                        // try again
+                        parent = parent.getParent();
+                    }
+                }
+
+                // did we get a fontValue from the preceding block (from the hack)?
+                // if not, get it from our cachEntry or choose the default.cd
+                if (fontValue == null && cacheEntry != null) {
+                    fontValue = cacheEntry.getFont();
+                }
+                final Font font = (fontValue != null) ? (Font)fontValue.getValue() : Font.getDefault();
+
+
+                if (resolved.getConverter() != null)
+                    val = resolved.convert(font);
+                else
+                    val = cssMetaData.getConverter().convert(resolved, font);
+
+                final StyleOrigin origin = whence.get();
+                return new CalculatedValue(val, origin, resolved.isNeedsFont());
+                
+            } catch (ClassCastException cce) {
+                final String msg = formatUnresolvedLookupMessage(node, cssMetaData, style.getStyle(),resolved);
+                List<CssError> errors = null;
+                if ((errors = StyleManager.getErrors()) != null) {
+                    final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
+                    errors.add(error);
+                }
+                if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
+                    LOGGER.warning(msg);
+                    LOGGER.fine("node = " + node.toString());
+                    LOGGER.fine("cssMetaData = " + cssMetaData);
+                    LOGGER.fine("styles = " + getMatchingStyles(node, cssMetaData));
+                }
+                return SKIP;
+            } catch (IllegalArgumentException iae) {
+                final String msg = formatExceptionMessage(node, cssMetaData, style.getStyle(), iae);
+                List<CssError> errors = null;
+                if ((errors = StyleManager.getErrors()) != null) {
+                    final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
+                    errors.add(error);
+                }
+                if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
+                    LOGGER.warning("caught: ", iae);
+                    LOGGER.fine("styleable = " + cssMetaData);
+                    LOGGER.fine("node = " + node.toString());
+                }
+                return SKIP;
+            } catch (NullPointerException npe) {
+                final String msg = formatExceptionMessage(node, cssMetaData, style.getStyle(), npe);
+                List<CssError> errors = null;
+                if ((errors = StyleManager.getErrors()) != null) {
+                    final CssError error = new CssError.PropertySetError(cssMetaData, node, msg);
+                    errors.add(error);
+                }
+                if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
+                    LOGGER.warning("caught: ", npe);
+                    LOGGER.fine("styleable = " + cssMetaData);
+                    LOGGER.fine("node = " + node.toString());
+                }
+                return SKIP;
+            } finally {
+                resolved.setResolved(null);
+            }
+                
+        }
+        // either cssValue was null or cssValue's value was "null"
+        return new CalculatedValue(null, style.getOrigin(), false);
+           
+    }
+    
+    /** return true if the origin of the property is USER */
+    private boolean isUserSetProperty(Node node, CssMetaData styleable) {
+        StyleableProperty styleableProperty = node != null ? styleable.getStyleableProperty(node) : null;
+        // writable could be null if this is a sub-property
+        StyleOrigin origin = styleableProperty != null ? styleableProperty.getStyleOrigin() : null;
+        return (origin == StyleOrigin.USER);    
+    }    
+            
+    private static final CssMetaData dummyFontProperty =
+            new FontCssMetaData<Node>("-fx-font", Font.getDefault()) {
+
+        @Override
+        public boolean isSettable(Node node) {
+            return true;
+        }
+
+        @Override
+        public StyleableProperty<Font> getStyleableProperty(Node node) {
+            return null;
+        }
+    };
+   
+    private StyleCacheEntry getParentCacheEntry(Node child) {
+
+        if (child == null) return null;
+        
+        StyleCacheEntry parentCacheEntry = null;
+        Node parent = child;
+        CssStyleHelper parentHelper = null;
+        
+        do {
+            parent = parent.getParent();
+            if (parent != null) {
+                parentHelper = parent.styleHelper;
+                if (parentHelper != null) {
+                    parentCacheEntry = parentHelper.getStyleCacheEntry(parent, null);
+                }
+            }
+        } while (parent != null && parentCacheEntry == null);
+
+        return parentCacheEntry;
+    }
+   
+    private CalculatedValue getFontForUseInConvertingRelativeSize(
+             final Node node,
+             final StyleCacheEntry cacheEntry,
+             Set<PseudoClass> pseudoclassState,
+            Map<String,CascadingStyle> inlineStyles)
+     {
+        
+        // To make the code easier to read, define CONSIDER_INLINE_STYLES as true. 
+        // Passed to lookupFontSubProperty to tell it whether or not 
+        // it should look for inline styles
+        final boolean CONSIDER_INLINE_STYLES = true;
+        
+        StyleOrigin origin = null;
+        Font foundFont = null;
+        CalculatedValue foundSize = null;
+        CalculatedValue foundShorthand = null;
+        boolean isRelative = false;
+         
+        // RT-20145 - if looking for font size and the node has a font, 
+        // use the font property's value if it was set by the user and
+        // there is not an inline or author style.
+        if (cacheMetaData.fontProp != null) {
+            StyleableProperty<Font> styleableProp = cacheMetaData.fontProp.getStyleableProperty(node);
+            StyleOrigin fpOrigin = styleableProp.getStyleOrigin();
+            if (fpOrigin == StyleOrigin.USER) {                
+                origin = fpOrigin;
+                foundFont = styleableProp.getValue();
+            }
+        } 
+ 
+        final CascadingStyle fontShorthand =
+            getStyle(node, "-fx-font", pseudoclassState, inlineStyles);
+
+        if (fontShorthand != null) {
+            
+            final CalculatedValue cv = 
+                calculateValue(fontShorthand, node, dummyFontProperty, 
+                    pseudoclassState, inlineStyles, 
+                    node, cacheEntry, null);
+            
+            // If we don't have an existing font, or if the origin of the
+            // existing font is less than that of the shorthand, then
+            // take the shorthand. If the origins compare equals, then take 
+            // the shorthand since the fontProp value will not have been
+            // updated yet.
+            // Man, this drove me nuts!
+            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {
+                               
+                // cv could be SKIP
+                if (cv.getValue() instanceof Font) {
+                    origin = cv.getOrigin();
+                    foundShorthand = cv;
+                    foundFont = null;
+                }
+
+            }  
+         }
+ 
+        final boolean isUserSet = 
+                origin == StyleOrigin.USER || origin == StyleOrigin.INLINE;
+
+        // now look for -fx-size, but don't look past the current node (hence 
+        // distance == 0 and negation of CONSIDER_INLINE_STYLES)        
+        CascadingStyle fontSize = lookupFontSubPropertyStyle(node, "-fx-font-size",
+                isUserSet, fontShorthand, 0, !CONSIDER_INLINE_STYLES);
+        
+        if (fontSize != null) {
+
+            final CalculatedValue cv = 
+                calculateValue(fontSize, node, dummyFontProperty, pseudoclassState, inlineStyles, 
+                    node, cacheEntry, null);
+            
+            if (cv.getValue() instanceof Double) {
+                if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {  
+                    origin = cv.getOrigin();
+                    foundSize = cv;
+                    foundShorthand = null;
+                    foundFont = null;
+                }
+             }
+
+         }
+         
+         
+        if (foundShorthand != null) {
+            
+            return foundShorthand;
+            
+        } else if (foundSize != null) {
+            
+            Font font = Font.font("system", ((Double)foundSize.getValue()).doubleValue());
+            return new CalculatedValue(font, foundSize.getOrigin(), foundSize.isRelative());
+            
+        } else if (foundFont != null) {
+         
+            // Did this found font come from a style? 
+            // If so, then the font used to convert it from a relative size
+            // (if conversion was needed) comes from the parent.
+            if (origin != null && origin != StyleOrigin.USER) {
+                
+                StyleCacheEntry parentCacheEntry = getParentCacheEntry(node);
+
+                if (parentCacheEntry != null && parentCacheEntry.getFont() != null) {
+                    isRelative = parentCacheEntry.getFont().isRelative();
+                } 
+            }
+            return new CalculatedValue(foundFont, origin, isRelative);
+            
+        } else {
+            
+            // no font, font-size or fontProp. 
+            // inherit by taking the parent's cache entry font.
+            StyleCacheEntry parentCacheEntry = getParentCacheEntry(node);
+            
+            if (parentCacheEntry != null && parentCacheEntry.getFont() != null) {
+                return parentCacheEntry.getFont();                    
+            } 
+        } 
+        // last ditch effort -  take the default font.
+        return new CalculatedValue(Font.getDefault(), null, false);
+     }
+
+    
+    private CascadingStyle lookupFontSubPropertyStyle(final Node node, 
+            final String subProperty, final boolean isUserSet,
+            final CascadingStyle csShorthand, 
+            final int distance,
+            boolean considerInlineStyles) {
+    
+        Node parent = node;
+        CssStyleHelper helper = this;
+        int nlooks = 0;
+        CascadingStyle returnValue = null;
+        StyleOrigin origin = null;
+        boolean consideringInline = false;
+        
+        while (parent != null && (consideringInline || nlooks <= distance)) {
+            
+            final Set<PseudoClass> states = parent.pseudoClassStates;
+            final Map<String,CascadingStyle> inlineStyles = CssStyleHelper.getInlineStyleMap(parent);
+            
+            CascadingStyle cascadingStyle = 
+                helper.getStyle(parent, subProperty, states, inlineStyles);
+            
+            if (isUserSet) {
+                //
+                // Don't look past this node if the user set the property.
+                //
+                if (cascadingStyle != null) {
+                    
+                    origin = cascadingStyle.getOrigin();
+
+                    // if the user set the property and the origin is the
+                    // user agent stylesheet, then we can't use the style
+                    // since ua styles shouldn't override user set values
+                    if (origin == StyleOrigin.USER_AGENT) {
+                        returnValue = null;
+                    }
+                }    
+                
+                break;
+                
+            } else if (cascadingStyle != null) {
+
+                //
+                // If isUserSet is false, then take the style if we found one.
+                // If csShorthand is not null, then were looking for an inline
+                // style. In this case, if the origin is INLINE, we'll take it.
+                // If it isn't INLINE we'll keep looking for an INLINE style.
+                //
+                final boolean isInline = cascadingStyle.getOrigin() == StyleOrigin.INLINE;
+                if (returnValue == null || isInline) {
+                    origin = cascadingStyle.getOrigin();
+                    returnValue = cascadingStyle;
+                    
+                    // If we found and inline style, then we don't need to look 
+                    // further. Also, if the style is not an inline style and we
+                    // don't want to consider inline styles, then look no further.
+                    if (isInline || considerInlineStyles == false) {
+                        
+                        break;
+                        
+                    } else {
+                        // 
+                        // If we are here, then the style is not an inline style
+                        // and we do want to consider inline styles. Setting
+                        // this flag will cause the code to look beyond nlooks
+                        // to see if there is an inline style
+                        //
+                        consideringInline = true;
+                    }
+                } 
+                
+            }
+                
+            // 
+            // haven't found it yet, or we're looking for an inline style
+            // so keep looking up the parent chain.
+            //
+            do {
+                parent = parent.getParent();
+                nlooks += 1;
+                helper = parent != null ? parent.styleHelper : null;
+            } while (parent != null && helper == null);
+        }
+        
+        if (csShorthand != null && returnValue != null) {
+       
+            final boolean shorthandImportant = 
+                    csShorthand.getStyle().getDeclaration().isImportant();
+            
+            final Style style = returnValue.getStyle();
+            final boolean returnValueIsImportant = 
+                style.getDeclaration().isImportant();
+
+            if (nlooks < distance) {
+                //
+                // if we found a font sub-property closer to the node than 
+                // the font shorthand, then the sub-property style
+                // wins provided the fontShorthand isn't important.
+                // If font shorthand is important and sub-property style is 
+                // important, then sub-property style wins (since, being closer
+                // to the node, it is more specific)
+                //                
+                if (shorthandImportant == true && returnValueIsImportant == false) {
+                    returnValue = null;
+                } 
+
+            } else if (csShorthand.compareTo(returnValue) < 0) {
+                //
+                // CascadingStyle.compareTo is such that a return value less
+                // than zero means the style is more specific than the arg.
+                // So if csShorthand is more specific than the return value,
+                // return null.
+                // 
+                // if we found font sub-property at the same distance from the
+                // node as the font shortand, then do a normal compare
+                // to see if the sub-property is more specific. If it isn't
+                // then return null.
+                //
+                returnValue = null;
+                        
+            }
+
+        }
+        
+        return returnValue;
+        
+    }
+    
+    /**
+     * Look up a font property. This is handled separately from lookup since
+     * font is inherited and has sub-properties. One should expect that the 
+     * text font for the following would be 16px Arial. The lookup method would
+     * give 16px system since it would look <em>only</em> for font-size, 
+     * font-family, etc <em>only</em> if the lookup on font failed.
+     * <pre>
+     * Text text = new Text("Hello World");
+     * text.setStyle("-fx-font-size: 16px;");
+     * Group group = new Group();
+     * group.setStyle("-fx-font: 12px Arial;");
+     * group.getChildren().add(text);
+     * </pre>
+     * @param node
+     * @param styleable
+     * @param isUserSet
+     * @param states
+     * @param userStyles
+     * @param originatingNode
+     * @param cacheEntry
+     * @param styleList
+     * @return 
+     */
+    private CalculatedValue lookupFont(Node node, CssMetaData styleable, 
+            boolean isUserSet, Node originatingNode, 
+            StyleCacheEntry cacheEntry, List<Style> styleList) {
+
+        // To make the code easier to read, define CONSIDER_INLINE_STYLES as true. 
+        // Passed to lookupFontSubProperty to tell it whether or not 
+        // it should look for inline styles
+        final boolean CONSIDER_INLINE_STYLES = true; 
+        
+        StyleOrigin origin = null;
+        boolean isRelative = false;
+            
+        // distance keeps track of how far up the parent chain we had to go
+        // to find a font shorthand. We'll look no further than this
+        // for the missing pieces. nlooks is used to keep track of how 
+        // many parents we've looked at. nlooks should never exceed distance. 
+        int distance = 0, nlooks = 0;
+        
+        Node parent = node;
+        CssStyleHelper helper = this;
+        String property = styleable == null ? null : styleable.getProperty();
+        CascadingStyle csShorthand = null;
+        while (parent != null) {
+            
+            final Set<PseudoClass> states = parent.pseudoClassStates;
+            final Map<String,CascadingStyle> inlineStyles = CssStyleHelper.getInlineStyleMap(parent);
+            
+            final CascadingStyle cascadingStyle =
+                helper.getStyle(parent, property, states, inlineStyles);
+            
+            if (isUserSet) {
+                //
+                // If isUserSet, then we don't look beyond the current node. 
+                // Only if the user did not set the font will we inherit.
+                //
+                if (cascadingStyle != null) {
+                
+                    origin = cascadingStyle.getOrigin();
+
+                    // if the user set font and the origin of the font shorthand
+                    // is the user agent stylesheet, then we can't use the style
+                    // since ua styles shouldn't override setFont
+                    if (origin != StyleOrigin.USER_AGENT) {
+                        csShorthand = cascadingStyle;
+                    }                    
+                }    
+                
+                break;
+                
+            } else if (cascadingStyle != null) {
+                //
+                // If isUserSet is false, then take the style if we found one.
+                // If csShorthand is not null, then were looking for an inline
+                // style. In this case, if the origin is INLINE, we'll take it.
+                // If it isn't INLINE we'll keep looking for an INLINE style.
+                //
+                final boolean isInline = cascadingStyle.getOrigin() == StyleOrigin.INLINE;
+                if (csShorthand == null || isInline) {
+                    origin = cascadingStyle.getOrigin();
+                    csShorthand = cascadingStyle;
+                    distance = nlooks;
+                    
+                    if (isInline) {
+                        break;
+                    }
+                } 
+                
+                
+            } 
+            
+            //
+            // If were here, then we either didn't find a style or we did find
+            // one but it wasn't inline. Either way, we need to keep looking
+            // up the parent chain for the next -fx-font.
+            //
+            do {
+                parent = parent.getParent();
+                nlooks += 1;
+                helper = parent != null ? parent.styleHelper : null;
+            } while (parent != null && helper == null);
+
+        }
+
+        if (csShorthand == null) {
+            distance = nlooks;
+        }
+        nlooks = 0;
+        
+        final Set<PseudoClass> states = node.pseudoClassStates;
+        final Map<String,CascadingStyle> inlineStyles = getInlineStyleMap(node);
+
+        String family = null;
+        double size = -1;
+        FontWeight weight = null;
+        FontPosture style = null;
+        
+        if (csShorthand != null) {
+            
+            if (styleList != null) {
+                styleList.add(csShorthand.getStyle());
+            }
+            
+            // pull out the pieces. 
+            final CalculatedValue cv = 
+                calculateValue(csShorthand, node, styleable, states, inlineStyles, 
+                    originatingNode, cacheEntry, styleList);
+            
+            // UA < AUTHOR < INLINE
+            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {
+                
+                if (cv.getValue() instanceof Font) {
+                    Font f = (Font)cv.getValue();
+                    isRelative = cv.isRelative();
+                    origin = cv.getOrigin();
+                
+                    // what did font shorthand specify? 
+                    ParsedValueImpl[] vals = 
+                            (ParsedValueImpl[])csShorthand.getParsedValueImpl().getValue();
+                    // Use family and size from converted font since the actual 
+                    // values may have been resolved. The weight and posture, 
+                    // however, are hard to get reliably from the font so use 
+                    // the parsed value instead. 
+                    if (vals[0] != null) family = f.getFamily();
+                    if (vals[1] != null) size   = f.getSize();
+                    if (vals[2] != null) weight = (FontWeight)vals[2].convert(null);
+                    if (vals[3] != null) style  = (FontPosture)vals[3].convert(null);
+
+                }
+            }
+            
+        }
+        
+        CascadingStyle csFamily = null; 
+        if ((csFamily = lookupFontSubPropertyStyle(node, property+"-family",
+                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES)) != null) {
+
+            if (styleList != null) {
+                styleList.add(csFamily.getStyle());
+            }
+            
+            final CalculatedValue cv = 
+                calculateValue(csFamily, node, styleable, states, inlineStyles, 
+                    originatingNode, cacheEntry, styleList);
+
+            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
+                if (cv.getValue() instanceof String) {
+                    family = Utils.stripQuotes((String)cv.getValue());
+                    origin = cv.getOrigin();
+                }
+            }
+                
+        }
+        
+        CascadingStyle csSize = null;
+        if ((csSize = lookupFontSubPropertyStyle(node, property+"-size",
+                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
+       
+            if (styleList != null) {
+                styleList.add(csSize.getStyle());
+            }
+
+            final CalculatedValue cv = 
+                calculateValue(csSize, node, styleable, states, inlineStyles, 
+                    originatingNode, cacheEntry, styleList);
+
+            // UA < AUTHOR < INLINE
+            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
+                if (cv.getValue() instanceof Double) {
+                    size = ((Double)cv.getValue()).doubleValue();
+                    isRelative = cv.isRelative();
+                    origin = cv.getOrigin();
+                }
+            }
+
+        }
+        
+        CascadingStyle csWeight = null;
+        if ((csWeight = lookupFontSubPropertyStyle(node, property+"-weight",
+                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
+
+            if (styleList != null) {
+                styleList.add(csWeight.getStyle());
+            }
+            
+            final CalculatedValue cv = 
+                calculateValue(csWeight, node, styleable, states, inlineStyles, 
+                    originatingNode, cacheEntry, styleList);
+
+            // UA < AUTHOR < INLINE
+            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
+                if (cv.getValue() instanceof FontWeight) {
+                    weight = (FontWeight)cv.getValue();
+                    origin = cv.getOrigin();
+                }
+            }
+                
+        }
+
+        CascadingStyle csStyle = null;
+        if ((csStyle = lookupFontSubPropertyStyle(node, property+"-style",
+                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
+            
+            if (styleList != null) {
+                styleList.add(csStyle.getStyle());
+            }
+            
+            final CalculatedValue cv = 
+                calculateValue(csStyle, node, styleable, states, inlineStyles, 
+                    originatingNode, cacheEntry, styleList);
+
+            // UA < AUTHOR < INLINE
+            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {                        
+                if (cv.getValue() instanceof FontPosture) {
+                    style = (FontPosture)cv.getValue();
+                    origin = cv.getOrigin();
+                }
+            }                
+
+        }
+        
+        // if no styles were found, then skip...
+        if (family == null &&
+            size   == -1   &&
+            weight == null &&
+            style  == null) {
+            return SKIP;
+        }
+        
+        // Now we have all the pieces from the stylesheet
+        // still be some missing. We'll grab those from the node. 
+        StyleableProperty styleableProperty = styleable != null 
+                ? styleable.getStyleableProperty(node) 
+                : null;
+        Font f = null;
+        if (styleableProperty != null) {
+            f = (Font)styleableProperty.getValue();
+        }
+        if (f == null) f = Font.getDefault();
+
+        if (family == null) {
+            family = f.getFamily();
+        }
+
+        if (size == -1) {
+            size = f.getSize();                
+        }
+
+        Font val = null;
+        if (weight != null && style != null) {
+            val = Font.font(family, weight, style, size);            
+        } else if (weight != null) {
+            val = Font.font(family, weight, size);
+        } else if (style != null) {
+            val = Font.font(family, style, size);
+        } else {
+            val = Font.font(family, size);            
+        }
+
+        return new CalculatedValue(val, origin, isRelative);
+    }    
+    
+    /**
+     * Called from CssMetaData getMatchingStyles
+     * @param node
+     * @param styleableProperty
+     * @return 
+     */
+    List<Style> getMatchingStyles(Styleable node, CssMetaData styleableProperty) {
+        
+        final List<CascadingStyle> styleList = new ArrayList<CascadingStyle>();
+
+        getMatchingStyles(node, styleableProperty, styleList);
+
+        List<CssMetaData<? extends Styleable, ?>> subProperties = styleableProperty.getSubProperties();
+        if (subProperties != null) {
+            for (int n=0,nMax=subProperties.size(); n<nMax; n++) {
+                final CssMetaData subProperty = subProperties.get(n);
+                getMatchingStyles(node, subProperty, styleList);                    
+            }
+        }
+
+        Collections.sort(styleList);
+
+        final List<Style> matchingStyles = new ArrayList<Style>(styleList.size());
+        for (int n=0,nMax=styleList.size(); n<nMax; n++) {
+            final Style style = styleList.get(n).getStyle();
+            if (!matchingStyles.contains(style)) matchingStyles.add(style);
+        }
+
+        return matchingStyles;
+    }
+    
+    private void getMatchingStyles(Styleable node, CssMetaData styleableProperty, List<CascadingStyle> styleList) {
+        
+        if (node != null) {
+            
+            Map<String,List<CascadingStyle>> inlineStyleMap = null;
+            
+            // create a map of inline styles.
+            Styleable parent = node;
+            while (parent != null) {
+                
+                CssStyleHelper parentHelper = (parent instanceof Node) ?
+                        ((Parent)parent).styleHelper
+                        : null;
+                
+                if (parentHelper != null) {
+                    
+                    Map<String,CascadingStyle> inlineStyles = CssStyleHelper.getInlineStyleMap(parent);
+                    
+                    if (inlineStyles != null) {
+                        
+                        if (inlineStyleMap == null) {
+                            inlineStyleMap = new HashMap<String,List<CascadingStyle>>();
+                        }
+                        
+                        for(Entry<String,CascadingStyle> entry : inlineStyles.entrySet()) {                            
+                            String kee = entry.getKey();
+                            
+                            List<CascadingStyle> inlineStyleList = inlineStyleMap.get(kee);
+                            if (inlineStyleList == null) {
+                                inlineStyleList = new ArrayList<CascadingStyle>();
+                                inlineStyleMap.put(kee, inlineStyleList);
+                            }
+                            inlineStyleList.add(entry.getValue());
+                        }
+                    }
+                }
+                parent = parent.getStyleableParent();
+            }
+                    
+            String property = styleableProperty.getProperty();
+            final Map<String, List<CascadingStyle>> smap = getStyleMap();
+            if (smap == null) return;
+            
+             List<CascadingStyle> styles = smap.get(property);            
+            
+//            if (inlineStyleMap != null) {
+//               if (inlineStyleMap.containsKey(property)) {
+//                    List<CascadingStyle> inlineStyleList = inlineStyleMap.get(property);
+//                    if (styles == null) styles = new ArrayList<CascadingStyle>();
+//                    styles.addAll(inlineStyleList);
+//                }
+//            }
+
+            if (styles != null) {
+                styleList.addAll(styles);
+                for (int n=0, nMax=styles.size(); n<nMax; n++) {
+                    final CascadingStyle style = styles.get(n);
+                    final ParsedValueImpl parsedValue = style.getParsedValueImpl();
+                    getMatchingLookupStyles(node, parsedValue, inlineStyleMap, styleList);
+                }
+            }
+            
+            if (styleableProperty.isInherits()) {
+                parent = node.getStyleableParent();
+                while (parent != null) {
+                    CssStyleHelper parentHelper = parent instanceof Node 
+                            ? ((Node)parent).styleHelper
+                            : null;
+                    if (parentHelper != null) {
+                        parentHelper.getMatchingStyles(parent, styleableProperty, styleList); 
+                    }
+                    parent = parent.getStyleableParent();
+                }
+            }
+            
+        }
+
+    }
+    
+    // Pretty much a duplicate of resolveLookups, but without the state
+    private void getMatchingLookupStyles(Styleable node, ParsedValueImpl parsedValue, Map<String,List<CascadingStyle>> inlineStyleMap, List<CascadingStyle> styleList) {
+                
+        if (parsedValue.isLookup()) {
+            
+            Object value = parsedValue.getValue();
+            
+            if (value instanceof String) {
+                
+                final String property = (String)value;
+                // gather up any and all styles that contain this value as a property
+                Styleable parent = node;
+                do {
+                    final CssStyleHelper helper = parent instanceof Node 
+                            ? ((Node)parent).styleHelper
+                            : null;
+                    if (helper != null) {
+                                             
+                        final int start = styleList.size();
+                        
+                        final Map<String, List<CascadingStyle>> smap = helper.getStyleMap();
+                        if (smap != null) {
+
+                            List<CascadingStyle> styles = smap.get(property);
+
+                            if (styles != null) {
+                                styleList.addAll(styles);
+                            }
+
+                        }
+                        
+                        List<CascadingStyle> inlineStyles = (inlineStyleMap != null) 
+                            ? inlineStyleMap.get(property) 
+                            : null;
+                        
+                        if (inlineStyles != null) {
+                            styleList.addAll(inlineStyles);
+                        }
+                        
+                        final int end = styleList.size();
+                        
+                        for (int index=start; index<end; index++) {
+                            final CascadingStyle style = styleList.get(index);
+                            getMatchingLookupStyles(parent, style.getParsedValueImpl(), inlineStyleMap, styleList);
+                        }
+                    }
+                                                                                    
+                } while ((parent = parent.getStyleableParent()) != null);
+            
+            }
+        }
+        
+        // If the value doesn't contain any values that need lookup, then bail
+        if (!parsedValue.isContainsLookups()) {
+            return;
+        }
+
+        final Object val = parsedValue.getValue();
+        if (val instanceof ParsedValueImpl[][]) {
+        // If ParsedValueImpl is a layered sequence of values, resolve the lookups for each.
+            final ParsedValueImpl[][] layers = (ParsedValueImpl[][])val;
+            for (int l=0; l<layers.length; l++) {
+                for (int ll=0; ll<layers[l].length; ll++) {
+                    if (layers[l][ll] == null) continue;
+                        getMatchingLookupStyles(node, layers[l][ll], inlineStyleMap, styleList);
+                }
+            }
+
+        } else if (val instanceof ParsedValueImpl[]) {
+        // If ParsedValueImpl is a sequence of values, resolve the lookups for each.
+            final ParsedValueImpl[] layer = (ParsedValueImpl[])val;
+            for (int l=0; l<layer.length; l++) {
+                if (layer[l] == null) continue;
+                    getMatchingLookupStyles(node, layer[l], inlineStyleMap, styleList);
+            }
+        }
+
+    }
+    
+}
--- a/javafx-ui-common/src/javafx/scene/Node.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Fri Feb 22 15:41:59 2013 -0500
@@ -103,12 +103,11 @@
 import com.sun.javafx.binding.ExpressionHelper;
 import com.sun.javafx.collections.TrackableObservableList;
 import com.sun.javafx.collections.UnmodifiableListSet;
+import com.sun.javafx.css.PseudoClassState;
 import javafx.css.ParsedValue;
 import com.sun.javafx.css.Selector;
 import com.sun.javafx.css.Style;
 import javafx.css.StyleConverter;
-import com.sun.javafx.css.StyleHelper;
-import com.sun.javafx.css.StyleManager;
 import javafx.css.Styleable;
 import javafx.css.StyleableBooleanProperty;
 import javafx.css.StyleableDoubleProperty;
@@ -893,6 +892,7 @@
         }
     };
     
+    @Override
     public final ObservableList<String> getStyleClass() { 
         return styleClass; 
     }
@@ -2206,7 +2206,6 @@
         //if (PerformanceTracker.isLoggingEnabled()) {
         //    PerformanceTracker.logEvent("Node.init for [{this}, id=\"{id}\"]");
         //}
-        styleHelper = new StyleHelper(this);
         setDirty();
         updateTreeVisible();
         //if (PerformanceTracker.isLoggingEnabled()) {
@@ -7974,6 +7973,26 @@
         return getClassCssMetaData();
     }
      
+    /**
+     * @return  The Styles that match this CSS property for the given Node. The 
+     * list is sorted by descending specificity. 
+     * @treatAsPrivate implementation detail
+     * @deprecated This is an experimental API that is not intended for general use and is subject to change in future versions
+     */
+     @Deprecated // SB-dependency: RT-21096 has been filed to track this
+    public static List<Style> impl_getMatchingStyles(CssMetaData cssMetaData, Styleable styleable) {
+        if (styleable != null && cssMetaData != null && styleable instanceof Node) {
+            
+            Node node = (Node)styleable;
+            
+            if (node.styleHelper != null) { 
+                return node.styleHelper.getMatchingStyles(node, cssMetaData);
+            }
+            
+        }
+        return Collections.<Style>emptyList();
+    }    
+    
      /**
       * RT-17293
       * @treatAsPrivate implementation detail
@@ -8051,19 +8070,26 @@
      */
     public final void pseudoClassStateChanged(PseudoClass pseudoClass, boolean active) {
         
-        final boolean isTransition = styleHelper.pseudoClassStateChanged(pseudoClass, active);
-        if (isTransition) {
-            requestCssStateTransition();
-        }            
+        final boolean modified = active 
+                ? pseudoClassStates.add(pseudoClass) 
+                : pseudoClassStates.remove(pseudoClass);
         
+        if (modified && styleHelper != null) {
+            final boolean isTransition = styleHelper.pseudoClassStateChanged(pseudoClass);
+            if (isTransition) {
+                requestCssStateTransition();
+            }            
+        }        
    }
     
+    // package so that StyleHelper can get at it
+    final Set<PseudoClass> pseudoClassStates = new PseudoClassState();
     /**
      * @return An unmodifiable Set of active pseudo-class states
      */
     public final Set<PseudoClass> getPseudoClassStates() {
         
-        return styleHelper.getPseudoClassState();
+        return Collections.unmodifiableSet(pseudoClassStates);
         
     }
 
@@ -8088,11 +8114,6 @@
         }
     }
 
-//    // this function primarily exists as a hook to aid in testing
-//    boolean isPseudoclassUsed(PseudoClass pseudoclass) {
-//        return (styleHelper != null) ? styleHelper.isPseudoClassUsed(pseudoclass) : false;
-//    }
-
     /**
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
@@ -8223,13 +8244,13 @@
         // or if my own flag indicates I need to reapply
         if (cssFlag == CssFlags.REAPPLY) {
 
-            final StyleManager styleManager = StyleManager.getInstance();
-            styleHelper.setStyles(this);
+            styleHelper = CssStyleHelper.createStyleHelper(this);
 
         } else if (cssFlag == CssFlags.RECALCULATE) {
-            
-            final StyleManager styleManager = StyleManager.getInstance();
-            styleHelper.inlineStyleChanged(this);
+
+            if (styleHelper != null) {
+                styleHelper.inlineStyleChanged(this);
+            }
             
         }
         
@@ -8238,27 +8259,18 @@
         cssFlag = CssFlags.CLEAN;
 
         // Transition to the new state and apply styles
-        styleHelper.transitionToState(this);
-    }
-    
+        if (styleHelper != null) {
+            styleHelper.transitionToState(this);
+        }
+    }
+        
     /**
      * A StyleHelper for this node.
      * A StyleHelper contains all the css styles for this node
      * and knows how to apply them when our state changes.
      */
-    private final StyleHelper styleHelper;
-    
-
-    /**
-     * Get this nodes 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
-    public StyleHelper impl_getStyleHelper() {
-        return styleHelper;
-    }
-
+    CssStyleHelper styleHelper;
+        
     private static final PseudoClass HOVER_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("hover");
     private static final PseudoClass PRESSED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("pressed");
     private static final PseudoClass DISABLED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("disabled");
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/CssMetaDataTest.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/CssMetaDataTest.java	Fri Feb 22 15:41:59 2013 -0500
@@ -53,6 +53,8 @@
 import com.sun.javafx.jmx.MXNodeAlgorithm;
 import com.sun.javafx.jmx.MXNodeAlgorithmContext;
 import com.sun.javafx.sg.PGNode;
+import java.util.Set;
+import javafx.css.PseudoClass;
 import javafx.scene.Scene;
 import javafx.scene.text.Text;
 import javafx.stage.Stage;
@@ -269,32 +271,17 @@
     static int ord = 0;
     static CascadingStyle createCascadingStyle(Selector selector, Declaration declaration) {
         
-        long[] pseudoClasses = null;
+        Set<PseudoClass> pseudoClasses = null;
         if (selector instanceof SimpleSelector) {
             
             pseudoClasses = ((SimpleSelector)selector).getPseudoClassStates();
         } else {
             
-            pseudoClasses = new long[0];
+            pseudoClasses = new PseudoClassState();
             for (SimpleSelector sel : ((CompoundSelector)selector).getSelectors()) {
                 
-                 long[] selectorPseudoClasses = sel.getPseudoClassStates();
-                 if (pseudoClasses.length < selectorPseudoClasses.length) {
-                     
-                     long[] temp = Arrays.copyOf(selectorPseudoClasses, selectorPseudoClasses.length);
-                     for (int n=0; n<pseudoClasses.length; n++) {
-                         temp[n] |= pseudoClasses[n];
-                     }
-                     pseudoClasses = temp;
-                     
-                 } else {
-                     
-                     int nMax = Math.min(selectorPseudoClasses.length, pseudoClasses.length);
-                     for (int n=0; n<nMax; n++) {
-                         pseudoClasses[n] |= selectorPseudoClasses[n];
-                     }                     
-                     
-                 }
+                 Set<PseudoClass> selectorPseudoClasses = sel.getPseudoClassStates();
+                 pseudoClasses.addAll(selectorPseudoClasses);
             }
         }
         
@@ -397,7 +384,7 @@
         stage.show();
         
         final CssMetaData FILL = get(rectangle.getCssMetaData(), "-fx-fill");
-        final List<Style> actuals = StyleManager.getInstance().getInstance().getMatchingStyles(FILL, rectangle);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FILL, rectangle);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -517,7 +504,7 @@
         stage.show();        
                 
         final CssMetaData FILL = get(rectangle.getCssMetaData(), "-fx-fill");
-        final List<Style> actuals = StyleManager.getInstance().getInstance().getMatchingStyles(FILL, rectangle);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FILL, rectangle);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -640,7 +627,7 @@
         stage.show();
 
         final CssMetaData FILL = get(rectangle.getCssMetaData(), "-fx-fill");
-        final List<Style> actuals = StyleManager.getInstance().getInstance().getMatchingStyles(FILL, rectangle);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FILL, rectangle);
                 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -767,7 +754,7 @@
         stage.show();
         
         final CssMetaData FILL = get(rectangle.getCssMetaData(), "-fx-fill");
-        final List<Style> actuals = StyleManager.getInstance().getInstance().getMatchingStyles(FILL, rectangle);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FILL, rectangle);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -878,7 +865,7 @@
         stage.show();
                 
         final CssMetaData FILL = get(rectangle.getCssMetaData(), "-fx-fill");
-        final List<Style> actuals = StyleManager.getInstance().getInstance().getMatchingStyles(FILL, rectangle);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FILL, rectangle);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -986,7 +973,7 @@
         stage.show();
                 
         final CssMetaData FILL = get(rectangle.getCssMetaData(), "-fx-fill");
-        final List<Style> actuals = StyleManager.getInstance().getMatchingStyles(FILL, rectangle);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FILL, rectangle);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -1065,7 +1052,7 @@
         stage.show();
                 
         final CssMetaData FONT = get(text.getCssMetaData(), "-fx-font");
-        final List<Style> actuals = StyleManager.getInstance().getMatchingStyles(FONT, text);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FONT, text);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -1149,7 +1136,7 @@
         stage.show();
                         
         final CssMetaData FONT = get(text.getCssMetaData(), "-fx-font");
-        final List<Style> actuals = StyleManager.getInstance().getMatchingStyles(FONT, text);
+        final List<Style> actuals = Node.impl_getMatchingStyles(FONT, text);
 
 //        System.err.println("matchingStyles: " + matchingStyles);
 //        System.err.println("expecteds: " + expecteds);
@@ -1326,7 +1313,7 @@
         stage.show();
 
         CssMetaData prop = ((StyleableProperty)text.fillProperty()).getCssMetaData();
-        List list = StyleManager.getInstance().getMatchingStyles(prop, text);
+        List list = Node.impl_getMatchingStyles(prop, text);
         
         assertEquals(3, list.size(), 0);
                 
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/HonorDeveloperSettingsTest.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/HonorDeveloperSettingsTest.java	Fri Feb 22 15:41:59 2013 -0500
@@ -24,25 +24,18 @@
  */
 package com.sun.javafx.css;
 
-import com.sun.javafx.css.parser.CSSParser;
-import com.sun.javafx.tk.Toolkit;
-import java.io.IOException;
-import java.net.URL;
 import static org.junit.Assert.*;
 import javafx.scene.Cursor;
 import javafx.scene.Group;
 import javafx.scene.Scene;
-import javafx.scene.paint.Color;
 import javafx.scene.shape.Rectangle;
 import javafx.scene.text.Font;
 import javafx.scene.text.FontSmoothingType;
 import javafx.scene.text.Text;
 import javafx.stage.Stage;
 import javafx.stage.Window;
-import javafx.beans.value.*;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -240,7 +233,7 @@
         
         String url = getClass().getResource("HonorDeveloperSettingsTest_AUTHOR.css").toExternalForm();
         scene.getStylesheets().add(url);
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
         assertEquals(20, rect.getStrokeWidth(), 0.00001);
         
     }
@@ -253,7 +246,7 @@
         String url = getClass().getResource("HonorDeveloperSettingsTest_AUTHOR.css").toExternalForm();
         scene.getStylesheets().add(url);
            
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
         //
         // Stroke width is set to 1em in the author stylesheet. If 
         // RT-20145 is not working, then the code will pick up the 20px
@@ -272,7 +265,7 @@
         
         scene.getRoot().setStyle("-fx-font: 18 Amble;");
        
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
         
         //
         // If RT-20513 is not working, then the code will _not_ 
@@ -292,7 +285,7 @@
         
         scene.getRoot().setStyle("-fx-font: 18 Amble;");
         
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
                 
         assertEquals(14, text.getStrokeWidth(), 0.00001);
         
@@ -304,7 +297,7 @@
         text.setId("rt-20686-ua");
         text.setFontSmoothingType(FontSmoothingType.LCD);
         
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
          
         assertEquals(FontSmoothingType.LCD, text.getFontSmoothingType());
         
@@ -318,7 +311,7 @@
         text.setId("rt-20686-author");
         text.setFontSmoothingType(FontSmoothingType.GRAY);
         
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
                 
         assertEquals(FontSmoothingType.LCD, text.getFontSmoothingType());
         
@@ -330,7 +323,7 @@
         // text  has id "text". still, inline style should win out. 
         text.setStyle("-fx-font-size: 24;");
 
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
 
         double size = text.getFont().getSize();
         assertEquals(24, size, .0001);
@@ -346,7 +339,7 @@
         // want text to get font style from .root
         text.setId(null);
         
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
                 
         double size = text.getFont().getSize();
         assertEquals(20, size, .0001);
@@ -363,7 +356,7 @@
         text.setId(null);        
         text.setStyle("-fx-font-size: 24;");
 
-        Toolkit.getToolkit().firePulse();
+        scene.getRoot().impl_processCSS(true);
                
         double size = text.getFont().getSize();
         assertEquals(24, size, .0001);
@@ -382,7 +375,7 @@
         Group g = (Group)scene.getRoot();
         g.setStyle("-fx-font-size: 32;");
         
-        Toolkit.getToolkit().firePulse();
+        g.impl_processCSS(true);
                 
         double size = text.getFont().getSize();
         assertEquals(32, size, .0001);
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Fri Feb 22 15:41:59 2013 -0500
@@ -25,8 +25,6 @@
 
 package com.sun.javafx.css;
 
-import com.sun.javafx.css.StyleHelper.StyleCacheBucket;
-import com.sun.javafx.css.StyleHelper.StyleCacheKey;
 import com.sun.javafx.css.converters.FontConverter;
 import com.sun.javafx.css.converters.SizeConverter;
 import com.sun.javafx.tk.Toolkit;
@@ -72,7 +70,7 @@
             styles.add(
                 new CascadingStyle(
                     new Style(decl.rule.selectors.get(0), decl), 
-                    new long[0],
+                    new PseudoClassState(),
                     0, 
                     0
                 )
@@ -231,8 +229,8 @@
 
         final List<CascadingStyle> rootStyles = createStyleList(rootDecls);
         final Map<String,List<CascadingStyle>> rootStyleMap = createStyleMap(rootStyles);
-        final Map<StyleCacheKey, StyleCacheBucket> styleCache = 
-            new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheBucket>();
+        final Map<StyleCache.Key, StyleCache> styleCache = 
+            new HashMap<StyleCache.Key, StyleCache>();
         
         group = new Group();
         group.getStyleClass().add("root");
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/PseudoClassTest.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/PseudoClassTest.java	Fri Feb 22 15:41:59 2013 -0500
@@ -23,7 +23,8 @@
 
     @Before
     public void before() {
-        PseudoClassImpl.pseudoClassMap.clear();        
+        PseudoClassState.pseudoClassMap.clear();        
+        PseudoClassState.pseudoClasses.clear();       
     }
     
     @Test
@@ -35,7 +36,7 @@
 
     @Test
     public void testCreateStatesInstance() {
-        PseudoClassSet result = new PseudoClassSet();
+        PseudoClassState result = new PseudoClassState();
         assertNotNull(result);
     }
 
@@ -73,29 +74,40 @@
     }
 
     @Test
-    public void testPseudoClassSet_add() {
+    public void testPseudoClassState_add() {
         String pseudoClass = "xyzzy";
         PseudoClass state = PseudoClass.getPseudoClass(pseudoClass);
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         states.add(state);
-        List<PseudoClass> stateList = states.getPseudoClasses();
+        
+        List<PseudoClass> stateList = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = states.iterator();
+        while (iter.hasNext()) {
+            stateList.add(iter.next());
+        }
+        
         assertTrue(stateList.contains(state));
     }
 
     @Test
-    public void testPseudoClassSet_add_multipleStates() {
+    public void testPseudoClassState_add_multipleStates() {
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
         };
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
             states.add(state);
         }
         
-        List<PseudoClass> stateList = states.getPseudoClasses();
+        List<PseudoClass> stateList = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = states.iterator();
+        while (iter.hasNext()) {
+            stateList.add(iter.next());
+        }
+
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
             assertTrue(stateList.contains(state));
@@ -104,12 +116,12 @@
     }
     
     @Test
-    public void testPseudoClassSet_contains() {
+    public void testPseudoClassState_contains() {
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
         };
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -124,7 +136,7 @@
     }
     
     @Test
-    public void testPseudoClassSet_contains_negativeTest() {
+    public void testPseudoClassState_contains_negativeTest() {
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
         };
@@ -133,7 +145,7 @@
             "six", "seven", "eight"
         };
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -148,12 +160,12 @@
     }
 
     @Test
-    public void testPseudoClassSet_contains_null() {
+    public void testPseudoClassState_contains_null() {
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
         };
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -165,7 +177,7 @@
     }
     
     @Test
-    public void testPseudoClassSet_removeState() {
+    public void testPseudoClassState_removeState() {
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
         };
@@ -174,7 +186,7 @@
             "one", "two", "four", "five"
         };
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -194,13 +206,13 @@
     }
 
     @Test
-    public void testPseudoClassSet_containsAll() {
+    public void testPseudoClassState_containsAll() {
         
         String[] setA = new String[] {
             "zero", "one"
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -208,7 +220,7 @@
         String[] setB = new String[] {
             "zero", "one", "two", "three"            
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -217,13 +229,13 @@
     }    
 
     @Test
-    public void testPseudoClassSet_containsAll_negativeTest() {
+    public void testPseudoClassState_containsAll_negativeTest() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three" 
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -231,7 +243,7 @@
         String[] setB = new String[] {
             "zero", "one"            
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -240,13 +252,13 @@
     }    
 
     @Test
-    public void testPseudoClassSet_containsAll_whenSetsAreEqual() {
+    public void testPseudoClassState_containsAll_whenSetsAreEqual() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three" 
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -254,7 +266,7 @@
         String[] setB = new String[] {
             "zero", "one", "two", "three"            
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -263,13 +275,13 @@
     }    
 
     @Test
-    public void testPseudoClassSet_containsAll_whenSetsDisjoint() {
+    public void testPseudoClassState_containsAll_whenSetsDisjoint() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three" 
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -277,7 +289,7 @@
         String[] setB = new String[] {
             "four", "five", "six", "seven"            
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -286,7 +298,7 @@
     }        
         
     @Test
-    public void testPseudoClassSet_size() {
+    public void testPseudoClassState_size() {
         
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
@@ -294,7 +306,7 @@
 
         int expected = 5;
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -305,7 +317,7 @@
     }
     
     @Test
-    public void testPseudoClassSet_size_afterRemove() {
+    public void testPseudoClassState_size_afterRemove() {
         
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
@@ -313,7 +325,7 @@
 
         int expected = 4;
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -326,7 +338,7 @@
     }
 
     @Test
-    public void testPseudoClassSet_size_afterRemoveOnEmpty() {
+    public void testPseudoClassState_size_afterRemoveOnEmpty() {
         
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
@@ -334,7 +346,7 @@
 
         int expected = 0;
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -350,7 +362,7 @@
     }
 
     @Test
-    public void testPseudoClassSet_size_afterAddWhenAlreadyContains() {
+    public void testPseudoClassState_size_afterAddWhenAlreadyContains() {
         
         String[] pseudoClasses = new String[] {
             "one", "two", "three", "four", "five"
@@ -358,7 +370,7 @@
 
         int expected = 5;
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
@@ -372,21 +384,21 @@
     }
 
     @Test
-    public void testPseudoClassSet_isEmpty() {
-        PseudoClassSet states = new PseudoClassSet();
+    public void testPseudoClassState_isEmpty() {
+        PseudoClassState states = new PseudoClassState();
         assertTrue(states.isEmpty());
     }
 
     @Test
-    public void testPseudoClassSet_isEmpty_negativeTest() {
-        PseudoClassSet states = new PseudoClassSet();
+    public void testPseudoClassState_isEmpty_negativeTest() {
+        PseudoClassState states = new PseudoClassState();
         states.add(PseudoClass.getPseudoClass("pseudo-class"));
         assertTrue(states.isEmpty() == false);
     }
     
     @Test
-    public void testPseudoClassSet_isEmpty_whenBitMaskLengthGreaterThanOne() {
-        PseudoClassSet states = new PseudoClassSet();
+    public void testPseudoClassState_isEmpty_whenBitMaskLengthGreaterThanOne() {
+        PseudoClassState states = new PseudoClassState();
         PseudoClass state = null;
         try {
             for(int n=0; n<512; n++) {
@@ -401,13 +413,13 @@
     }
     
     @Test
-    public void testPseudoClassSet_equals() {
+    public void testPseudoClassState_equals() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three"
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -415,7 +427,7 @@
         String[] setB = new String[] {
             "zero", "one", "two", "three"            
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -424,13 +436,13 @@
     }    
     
     @Test
-    public void testPseudoClassSet_equals_negativeTest() {
+    public void testPseudoClassState_equals_negativeTest() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three"
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -438,7 +450,7 @@
         String[] setB = new String[] {
             "zero", "one", "two", "four"            
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -447,13 +459,13 @@
     }    
 
     @Test
-    public void testPseudoClassSet_retainAll() {
+    public void testPseudoClassState_retainAll() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three"
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -461,7 +473,7 @@
         String[] setB = new String[] {
             "four", "five", "one", "two", "three"
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -471,7 +483,11 @@
         };
         
         aStates.retainAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         
         assertEquals(expected.length, states.size(), 0.000001);
         
@@ -482,34 +498,42 @@
     }
     
     @Test
-    public void testPseudoClassSet_retainAll_withEmptyStates() {
+    public void testPseudoClassState_retainAll_withEmptyStates() {
         
-        PseudoClassSet bStates = new PseudoClassSet();
-        PseudoClassSet aStates = new PseudoClassSet();        
+        PseudoClassState bStates = new PseudoClassState();
+        PseudoClassState aStates = new PseudoClassState();        
         aStates.retainAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         assertEquals(0, states.size(), 0.000001);
     }
     
     @Test
-    public void testPseudoClassSet_retainAll_withNullArg() {
+    public void testPseudoClassState_retainAll_withNullArg() {
         
-        PseudoClassSet aStates = new PseudoClassSet();
-        PseudoClassSet bStates = null;
+        PseudoClassState aStates = new PseudoClassState();
+        PseudoClassState bStates = null;
         aStates.retainAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         assertEquals(0, states.size(), 0.000001);
         
     }
     
     @Test
-    public void testPseudoClassSet_retainAll_disjointYieldsEmpty() {
+    public void testPseudoClassState_retainAll_disjointYieldsEmpty() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three"
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -517,7 +541,7 @@
         String[] setB = new String[] {
             "four", "five"
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -525,7 +549,11 @@
         String[] expected = new String[0];
         
         aStates.retainAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         
         assertEquals(expected.length, states.size(), 0.000001);
         
@@ -536,13 +564,13 @@
     }
     
     @Test
-    public void testPseudoClassSet_addAll() {
+    public void testPseudoClassState_addAll() {
         
         String[] setA = new String[] {
             "zero", "one", "two", "three"
         };
         
-        PseudoClassSet aStates = new PseudoClassSet();
+        PseudoClassState aStates = new PseudoClassState();
         for(int n=0; n<setA.length; n++) {
             aStates.add(PseudoClass.getPseudoClass(setA[n]));
         }
@@ -550,7 +578,7 @@
         String[] setB = new String[] {
             "four", "five"
         };
-        PseudoClassSet bStates = new PseudoClassSet();
+        PseudoClassState bStates = new PseudoClassState();
         for(int n=0; n<setB.length; n++) {
             bStates.add(PseudoClass.getPseudoClass(setB[n]));
         }
@@ -561,7 +589,11 @@
         };
         
         aStates.addAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         
         assertEquals(expected.length, states.size(), 0.000001);
         
@@ -572,58 +604,74 @@
     }
     
     @Test
-    public void testPseudoClassSet_addAll_withEmptyStates() {
+    public void testPseudoClassState_addAll_withEmptyStates() {
         
-        PseudoClassSet bStates = new PseudoClassSet();
-        PseudoClassSet aStates = new PseudoClassSet();        
+        PseudoClassState bStates = new PseudoClassState();
+        PseudoClassState aStates = new PseudoClassState();        
         aStates.addAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         assertEquals(0, states.size(), 0.000001);
     }
     
     @Test
-    public void testPseudoClassSet_addAll_withNullArgs() {
+    public void testPseudoClassState_addAll_withNullArgs() {
         
-        PseudoClassSet aStates = new PseudoClassSet();
-        PseudoClassSet bStates = null;
+        PseudoClassState aStates = new PseudoClassState();
+        PseudoClassState bStates = null;
         aStates.addAll(bStates);
-        List<PseudoClass> states = aStates.getPseudoClasses();
+        List<PseudoClass> states = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = aStates.iterator();
+        while (iter.hasNext()) {
+            states.add(iter.next());
+        }
         assertEquals(0, states.size(), 0.000001);
         
     }
     
     @Test
-    public void testPseudoClassSet_getPseudoClasses() {
+    public void testPseudoClassState_getPseudoClasses() {
         
         String[] pseudoClasses = new String[] {
             "zero", "one", "two", "three"
         };
         List<PseudoClass> expected = new ArrayList<PseudoClass>();
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         for(int n=0; n<pseudoClasses.length; n++) {
             PseudoClass state = PseudoClass.getPseudoClass(pseudoClasses[n]);
             states.add(state);
             expected.add(state);            
         }
         
-        List<PseudoClass> stateList = states.getPseudoClasses();
+        List<PseudoClass> stateList = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = states.iterator();
+        while (iter.hasNext()) {
+            stateList.add(iter.next());
+        }
         
         assertTrue(expected.containsAll(stateList));
     }
         
     @Test
-    public void testPseudoClassSet_toString() {
+    public void testPseudoClassState_toString() {
         
         String[] pseudoClasses = new String[] {
             "zero", "one", "two", "three"
         };
         
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         for(int n=0; n<pseudoClasses.length; n++) {
             states.add(PseudoClass.getPseudoClass(pseudoClasses[n]));
         }
         
-        List<PseudoClass> stateList = states.getPseudoClasses();
+        List<PseudoClass> stateList = new ArrayList<PseudoClass>();
+        Iterator<PseudoClass> iter = states.iterator();
+        while (iter.hasNext()) {
+            stateList.add(iter.next());
+        }
         String expected = stateList.toString();
         
         String result = states.toString();
@@ -631,10 +679,10 @@
         assertEquals(expected, result);
     }
 
-    @Test public void testPseudoClassSet_iterator() {
+    @Test public void testPseudoClassState_iterator() {
         
         PseudoClass[] pseudoClasses = new PseudoClass[4];
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             pseudoClasses[n] = PseudoClass.getPseudoClass(Integer.toString(n));
@@ -656,10 +704,10 @@
         
     }
 
-    @Test public void testPseudoClassSet_iterator_withLargeNumberOfPsuedoClasses() {
+    @Test public void testPseudoClassState_iterator_withLargeNumberOfPsuedoClasses() {
         
         PseudoClass[] pseudoClasses = new PseudoClass[Long.SIZE*3];
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             pseudoClasses[n] = PseudoClass.getPseudoClass(Integer.toString(n));
@@ -681,10 +729,10 @@
         
     }
 
-    @Test public void testPseudoClassSet_iterator_remove() {
+    @Test public void testPseudoClassState_iterator_remove() {
         
         PseudoClass[] pseudoClasses = new PseudoClass[4];
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             pseudoClasses[n] = PseudoClass.getPseudoClass(Integer.toString(n));
@@ -709,10 +757,10 @@
         
     }
 
-    @Test public void testPseudoClassSet_iterator_remove_withLargeNumberOfPseudoClasses() {
+    @Test public void testPseudoClassState_iterator_remove_withLargeNumberOfPseudoClasses() {
         
         PseudoClass[] pseudoClasses = new PseudoClass[Long.SIZE*3];
-        PseudoClassSet states = new PseudoClassSet();
+        PseudoClassState states = new PseudoClassState();
         
         for (int n=0; n<pseudoClasses.length; n++) {
             pseudoClasses[n] = PseudoClass.getPseudoClass(Integer.toString(n));
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Fri Feb 22 15:41:59 2013 -0500
@@ -32,7 +32,6 @@
 import java.util.Collections;
 import java.util.List;
 import javafx.scene.Node;
-import javafx.scene.Scene;
 import org.junit.AfterClass;
 import org.junit.Test;
 import static org.junit.Assert.*;
@@ -135,17 +134,6 @@
     }
 
     @Ignore @Test
-    public void testMatches_Scene() {
-        System.out.println("matches");
-        Scene scene = null;
-        Rule instance = null;
-        List expResult = null;
-        List result = instance.matches(scene);
-        assertEquals(expResult, result);
-        fail("The test case is a prototype.");
-    }
-
-    @Ignore @Test
     public void testApplies() {
         System.out.println("applies");
         Node node = null;
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/SelectorPartitioningTest.java	Tue Feb 19 14:07:57 2013 -0500
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/SelectorPartitioningTest.java	Fri Feb 22 15:41:59 2013 -0500
@@ -26,16 +26,12 @@
 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;
@@ -206,7 +202,7 @@
                 
         SimpleSelector simple = simpleData.selector;
         
-        List<Rule> matched = instance.match(simple.getId(), simple.getName(), simple.getStyleClassMasks());
+        List<Rule> matched = instance.match(simple.getId(), simple.getName(), simple.getStyleClassSet());
         
         assertEquals(1,matched.size());
         Rule rule = matched.get(0);
@@ -228,7 +224,7 @@
                 
         SimpleSelector simple = complexData.selector;
         
-        List<Rule> matched = instance.match(simple.getId(), simple.getName(), simple.getStyleClassMasks());
+        List<Rule> matched = instance.match(simple.getId(), simple.getName(), simple.getStyleClassSet());
         assertEquals(complexData.matches, matched.size());
         
         for(Rule rule : matched) {