changeset 3982:eaea57901d09

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/scrum/controls/jfx/rt
author David Grieve<david.grieve@oracle.com>
date Wed, 12 Jun 2013 16:32:53 -0400
parents 749a762daa51 1ec38d2759eb
children 76a7ba878acd 544f08907253
files
diffstat 12 files changed, 907 insertions(+), 1122 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/com/sun/javafx/css/BitSet.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/BitSet.java	Wed Jun 12 16:32:53 2013 -0400
@@ -345,8 +345,8 @@
     public boolean retainAll(Collection<?> c) {
 
         if (c == null) {
-            // this not modified!
-            return false;
+            clear();
+            return true;
         }
         
         boolean modified = false;
@@ -361,11 +361,19 @@
 
             final long[] intersection = new long[max];
 
+
+            //
+            // Make sure modified is set if maskOne has more bits than maskTwo.
+            // If max is zero, then the loop that does the intersection is
+            // never entered (since maskTwo is empty). If modified isn't set,
+            // then the if (modified) block isn't entered and this.bits isn't
+            // set to the intersection.
+            //
+            modified |= (maskOne.length > max);
+
             for(int n = 0; n < max; n++) {
                 intersection[n] = maskOne[n] & maskTwo[n];
-                
                 modified |= intersection[n] != maskOne[n];
-                
             }
 
             if (modified) {
--- a/javafx-ui-common/src/com/sun/javafx/css/CalculatedValue.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/CalculatedValue.java	Wed Jun 12 16:32:53 2013 -0400
@@ -25,17 +25,18 @@
 package com.sun.javafx.css;
 
 import javafx.css.StyleOrigin;
+import javafx.scene.text.Font;
 
 public final class CalculatedValue {
 
     public static final CalculatedValue SKIP = new CalculatedValue(new int[0], null, false);
 
+
     public CalculatedValue(Object value, StyleOrigin origin, boolean relative) {
             
         this.value = value;            
         this.origin = origin;
         this.relative = relative;
-        
     }
 
     public Object getValue() {
@@ -50,8 +51,45 @@
         return relative;
     }
 
+    @Override public String toString() {
+        return
+            (new StringBuilder()
+                .append('{')
+                .append(String.valueOf(value))
+                .append(", ").append(origin)
+                .append(", ").append(relative)
+                .append('}')
+            ).toString();
+    }
+
+    @Override public boolean equals(Object obj) {
+
+        if(obj == null) {
+            return false;
+        }
+
+        if (this.getClass() != obj.getClass()) {
+            return false;
+        }
+
+        CalculatedValue other = (CalculatedValue)obj;
+
+        if (this.relative != other.relative)  {
+            return false;
+        }
+
+        if (this.origin != other.origin) {
+            return false;
+        }
+
+        if (this.value != null ? other.value == null : !this.value.equals(other.value)) {
+            return false;
+        }
+
+        return true;
+    }
+
     private final Object value;
     private final StyleOrigin origin;
     private final boolean relative;
-        
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/ParsedValueImpl.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/ParsedValueImpl.java	Wed Jun 12 16:32:53 2013 -0400
@@ -113,36 +113,34 @@
         return containsLookupsFlag;
     }
 
-    private final boolean needsFont;
-    public boolean isNeedsFont() {
-        if (resolved != null && resolved != this) {
-            return resolved.needsFont;
-        }
-        return needsFont;
-    }
-
-    private static boolean getNeedsFontFlag(Object obj) {
+    public static boolean containsFontRelativeSize(ParsedValue parsedValue, boolean percentUnitsAreRelative) {
 
         // Assume the value does not need a font for conversion
         boolean needsFont = false;
 
+        Object obj = parsedValue.getValue();
+
         if (obj instanceof Size) {
-            needsFont = ((Size)obj).isAbsolute() == false;
+            Size size = (Size)obj;
+            // percent is only relative for font and font-size properties
+            needsFont = size.getUnits() == SizeUnits.PERCENT
+                    ? percentUnitsAreRelative
+                    : size.isAbsolute() == false;
         }
 
-        else if(obj instanceof ParsedValueImpl) {
-            ParsedValueImpl value = (ParsedValueImpl)obj;
-            needsFont = value.needsFont;
+        else if(obj instanceof ParsedValue) {
+            ParsedValue value = (ParsedValueImpl)obj;
+            needsFont = containsFontRelativeSize(value, percentUnitsAreRelative);
         }
 
-        else if(obj instanceof ParsedValueImpl[]) {
-            ParsedValueImpl[] values = (ParsedValueImpl[])obj;
+        else if(obj instanceof ParsedValue[]) {
+            ParsedValue[] values = (ParsedValue[])obj;
             for(int v=0;
                 v<values.length && !needsFont;
                 v++)
             {
                 if (values[v] == null) continue;
-                needsFont = values[v].needsFont;
+                needsFont = containsFontRelativeSize(values[v], percentUnitsAreRelative);
             }
 
         } else if(obj instanceof ParsedValueImpl[][]) {
@@ -157,7 +155,7 @@
                     v++)
                 {
                     if (values[l][v] == null) continue;
-                    needsFont = values[l][v].needsFont;
+                    needsFont = containsFontRelativeSize(values[l][v], percentUnitsAreRelative);
                 }
             }
         }
@@ -176,7 +174,6 @@
         super(value, converter);
         this.lookup = lookup;
         this.containsLookups = lookup || getContainsLookupsFlag(value);
-        this.needsFont = getNeedsFontFlag(value);
     }
 
     /**
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleCache.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleCache.java	Wed Jun 12 16:32:53 2013 -0400
@@ -24,8 +24,10 @@
  */
 package com.sun.javafx.css;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import javafx.css.CssMetaData;
 
 /**
  * A cache to store values from lookup.
@@ -84,21 +86,26 @@
     
     public void clear() {
         if (entries == null) return;
+        Thread.dumpStack();
         entries.clear();
     }
         
-    public void putStyleCacheEntry(StyleCacheEntry.Key entryKey, StyleCacheEntry entry) {
+    public StyleCacheEntry getStyleCacheEntry(StyleCacheEntry.Key key) {
+
+        StyleCacheEntry entry = null;
+        if (entries != null) {
+            entry = entries.get(key);
+        }
+        return entry;
+    }
+
+    public void addStyleCacheEntry(StyleCacheEntry.Key key, StyleCacheEntry entry) {
         if (entries == null) {
-            this.entries = new HashMap<StyleCacheEntry.Key,StyleCacheEntry>();
+            entries = new HashMap<>(5);
         }
-        entries.put(entryKey, entry);
+        entries.put(key, entry);
     }
-    
-    public StyleCacheEntry getStyleCacheEntry(StyleCacheEntry.Key entryKey) {
-        if (entries == null) return null;
-        return entries.get(entryKey);
-    }
-    
+
     public static final class Key {
         
         public Key(int[] styleMapIds, int count) {
@@ -106,6 +113,14 @@
             System.arraycopy(styleMapIds, 0, this.styleMapIds, 0, count);
         }
 
+        public Key(Key other) {
+            this(other.styleMapIds, other.styleMapIds.length);
+        }
+
+        @Override public String toString() {
+            return Arrays.toString(styleMapIds);
+        }
+
         @Override
         public int hashCode() {
             int hash = 3;
@@ -120,37 +135,38 @@
 
         @Override
         public boolean equals(Object obj) {
-            
-            if (obj instanceof Key) {
 
-                final Key other = (Key) obj;
-            
-                // if one is null, so too must the other
-                if ((this.styleMapIds == null) ^ (other.styleMapIds == null)) {
+            if (obj == this) return true;
+
+            if (obj == null || obj.getClass() != this.getClass()) {
+                return false;
+            }
+
+            final Key other = (Key) obj;
+
+            // if one is null, so too must the other
+            if ((this.styleMapIds == null) ^ (other.styleMapIds == null)) {
+                return false;
+            }
+
+            // if one is null, so is the other
+            if (this.styleMapIds == null) {
+                return true;
+            }
+
+            for (int i=0; i<styleMapIds.length; i++) {
+                if (styleMapIds[i] != other.styleMapIds[i]) {
                     return false;
                 }
+            }
 
-                // if one is null, so is the other
-                if (this.styleMapIds == null) {
-                    return true;
-                }
+            return true;
 
-                for (int i=0; i<styleMapIds.length; i++) {
-                    if (styleMapIds[i] != other.styleMapIds[i]) {
-                        return false;
-                    }
-                }
-                
-                return true;
-            }
-            
-            return false;
-            
         }
         
         final int[] styleMapIds;
     }
     
     private Map<StyleCacheEntry.Key,StyleCacheEntry> entries;
-    
+
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleCacheEntry.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleCacheEntry.java	Wed Jun 12 16:32:53 2013 -0400
@@ -24,13 +24,12 @@
  */
 package com.sun.javafx.css;
 
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 import javafx.css.PseudoClass;
-import javafx.css.StyleOrigin;
+import javafx.scene.text.Font;
 
 /**
  *
@@ -38,90 +37,50 @@
 public final class StyleCacheEntry {
     
     public StyleCacheEntry() {
-        this(null);
-    }
-    
-    public StyleCacheEntry(StyleCacheEntry sharedCacheEntry) {
-        this.sharedCacheRef = sharedCacheEntry != null ? new WeakReference<StyleCacheEntry>(sharedCacheEntry) : null;
-    }   
-    
-    public CalculatedValue getFont() {
-        return font;
-    }
-    
-    public void setFont(CalculatedValue font) {
-        this.font = font;
     }
     
     public CalculatedValue get(String property) {
-//        if (values == null) return null;
-        
+
         CalculatedValue cv = null;
-        
-        if (values != null && ! values.isEmpty()) {
-            cv = values.get(property);
-        }
-        if (cv == null && sharedCacheRef != null) {
-            final StyleCacheEntry ce = sharedCacheRef.get();
-            if (ce != null && ce.values != null) {
-                cv = ce.values.get(property);
-            }
-            // if referent is null, we should skip the value.
-            // else cv = CalculatedValue.SKIP;
+        if (calculatedValues != null && ! calculatedValues.isEmpty()) {
+            cv = calculatedValues.get(property);
         }
         return cv;
     }
 
-    public void put(String property, CalculatedValue cv) {
+    public void put(String property, CalculatedValue calculatedValue) {
 
-        // If the origin of the calculated value is inline or user,
-        // then use local cache.
-        // If the origin of the calculated value is not inline or user,
-        // then use local cache if the font origin is inline or user and
-        // the value was calculated from a relative size unit.
-        final boolean isLocal =
-            (cv.getOrigin() == StyleOrigin.INLINE || cv.getOrigin() == StyleOrigin.USER)            
-            || (cv.isRelative() &&
-                (font.getOrigin() == StyleOrigin.INLINE || 
-                 font.getOrigin() == StyleOrigin.USER));
-        
-        if (isLocal) {
-            makeValuesMap();
-            values.put(property, cv);
-        } else {
-            // if isLocal is false, then sharedCacheRef cannot be null.
-            final StyleCacheEntry ce = sharedCacheRef.get();
-            ce.makeValuesMap();
-            if (ce != null && ce.values.containsKey(property) == false) {
-                // don't override value already in shared cache.
-                ce.values.put(property, cv);
-            }
+        if (calculatedValues == null) {
+            this.calculatedValues = new HashMap<>(5);
         }
-    }
-    
-    private void makeValuesMap() {
-        if (values == null) {
-            this.values = new HashMap<String, CalculatedValue>();
-        }
+
+        calculatedValues.put(property, calculatedValue);
     }
 
     public final static class Key {
 
         private final Set<PseudoClass>[] pseudoClassStates;
+        private final double fontSize;
     
-        public Key(Set<PseudoClass>[] pseudoClassStates, int count) {
-                        
-            this.pseudoClassStates = new PseudoClassState[count];
-            
-            for (int n=0; n<count; n++) {
+        public Key(Set<PseudoClass>[] pseudoClassStates, Font font) {
+
+            this.pseudoClassStates = new Set[pseudoClassStates.length];
+            for (int n=0; n<pseudoClassStates.length; n++) {
                 this.pseudoClassStates[n] = new PseudoClassState();
                 this.pseudoClassStates[n].addAll(pseudoClassStates[n]);
             }
+            this.fontSize = font != null ? font.getSize() : Font.getDefault().getSize();
+            
         }
-        
+
+        @Override public String toString() {
+            return Arrays.toString(pseudoClassStates) + ", " + fontSize;
+        }
+
         @Override
         public int hashCode() {
-            int hash = 7;
+            int hash = Double.hashCode(fontSize);
+
             final int iMax = pseudoClassStates != null ? pseudoClassStates.length : 0;
             
             for (int i=0; i<iMax; i++) {
@@ -136,45 +95,58 @@
 
         @Override
         public boolean equals(Object obj) {
-            
-            if (obj instanceof Key) {
-                
-                final Key other = (Key) obj;
 
-                // either both must be null or both must be not-null
-                if ((pseudoClassStates == null) ^ (other.pseudoClassStates == null)) {
+            if (obj == this) return true;
+
+            if (obj == null || obj.getClass() != this.getClass()) return false;
+
+            final Key other = (Key) obj;
+
+            //
+            // double == double is not reliable since a double is kind of
+            // a fuzzy value. And Double.compare is too precise.
+            // For javafx, most sizes are rounded to the nearest tenth
+            // (see SizeUnits.round) so comparing  here to the nearest
+            // millionth is more than adequate.
+            //
+            // We assume that both fsize values are > 0, which is a safe assumption
+            // because Font doesn't allow sizes < 0.
+            final double diff = fontSize - other.fontSize;
+            if (Math.abs(diff) > 0.000001) {
+                return false;
+            }
+
+            // either both must be null or both must be not-null
+            if ((pseudoClassStates == null) ^ (other.pseudoClassStates == null)) {
+                return false;
+            }
+
+            // if one is null, the other is too.
+            if (pseudoClassStates == null) {
+                return true;
+            }
+
+            if (pseudoClassStates.length != other.pseudoClassStates.length) {
+                return false;
+            }
+
+            for (int i=0; i<pseudoClassStates.length; 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 (this_pcs == null ? other_pcs != null : !this_pcs.equals(other_pcs)) {
                     return false;
                 }
+            }
 
-                // if one is null, the other is too. 
-                if (pseudoClassStates == null) {
-                    return true;
-                }
-
-                if (pseudoClassStates.length != other.pseudoClassStates.length) {
-                    return false;
-                }
-
-                for (int i=0; i<pseudoClassStates.length; 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 (this_pcs == null ? other_pcs != null : !this_pcs.equals(other_pcs)) {
-                        return false;
-                    }
-                }
-
-                return true;
-            }
-            
-            return false;
+            return true;
         }
 
     }
         
-    private final Reference<StyleCacheEntry> sharedCacheRef;
-    private Map<String,CalculatedValue> values;
-    private CalculatedValue  font; // for use in converting font relative sizes
+//    private final Reference<StyleCacheEntry> sharedCacheRef;
+    private Map<String,CalculatedValue> calculatedValues;
+//    private CalculatedValue  font; // for use in converting font relative sizes
 }
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Wed Jun 12 16:32:53 2013 -0400
@@ -170,13 +170,23 @@
     private static final Map<Scene, CacheContainer> cacheContainerMap
             = new WeakHashMap<Scene, CacheContainer>();
 
-    /**
-     * StyleHelper uses this cache but it lives here so it can be cleared
-     * when style-sheets change.
-     */
-    public Map<StyleCache.Key,StyleCache> getStyleCache(Scene scene) {
 
-        if (scene == null) return null;
+    private CacheContainer getCacheContainer(Styleable styleable) {
+
+        if (styleable == null) return null;
+
+        Scene scene = null;
+
+        if (styleable instanceof Node) {
+
+            Node node = (Node)styleable;
+            scene = node.getScene();
+
+        } else if (styleable instanceof Window) {
+            // this catches the PopupWindow case
+            scene = ((Window)styleable).getScene();
+        }
+        // todo: what other Styleables need to be handled here?
 
         CacheContainer container = cacheContainerMap.get(scene);
         if (container == null) {
@@ -184,14 +194,35 @@
             cacheContainerMap.put(scene, container);
         }
 
-        return container.getStyleCache();
+        return container;
+
     }
+    /** 
+     * StyleHelper uses this cache but it lives here so it can be cleared
+     * when style-sheets change.
+     */
+    public StyleCache getSharedCache(Styleable styleable, StyleCache.Key key) {
 
-    public StyleMap getStyleMap(Scene scene, int smapId) {
+        CacheContainer container = getCacheContainer(styleable);
+        if (container == null) return null;
 
-        if (scene == null || smapId == -1) return StyleMap.EMPTY_MAP;
+        Map<StyleCache.Key,StyleCache> styleCache = container.getStyleCache();
+        if (styleCache == null) return null;
 
-        CacheContainer container = cacheContainerMap.get(scene);
+        StyleCache sharedCache = styleCache.get(key);
+        if (sharedCache == null) {
+            sharedCache = new StyleCache();
+            styleCache.put(new StyleCache.Key(key), sharedCache);
+        }
+
+        return sharedCache;
+    }
+    
+    public StyleMap getStyleMap(Styleable styleable, int smapId) {
+
+        if (smapId == -1) return StyleMap.EMPTY_MAP;
+        
+        CacheContainer container = getCacheContainer(styleable);
         if (container == null) return StyleMap.EMPTY_MAP;
 
         return container.getStyleMap(smapId);
@@ -1287,6 +1318,24 @@
         return list;
     }
 
+    // return true if this node or any of its parents has an inline style.
+    private static Node nodeWithInlineStyles(Node node) {
+
+        Node parent = node;
+
+        while (parent != null) {
+
+            final String inlineStyle = parent.getStyle();
+            if (inlineStyle != null && inlineStyle.isEmpty() == false) {
+                return parent;
+            }
+            parent = parent.getParent();
+
+        }
+
+        return null;
+    }
+
     // reuse key to avoid creation of numerous small objects
     private Key key = null;
 
@@ -1300,10 +1349,10 @@
             return StyleMap.EMPTY_MAP;
         }
 
-        CacheContainer cacheContainer = cacheContainerMap.get(scene);
+        CacheContainer cacheContainer = getCacheContainer(node);
         if (cacheContainer == null) {
-            cacheContainer = new CacheContainer();
-            cacheContainerMap.put(scene, cacheContainer);
+            assert false : node.toString();
+            return StyleMap.EMPTY_MAP;
         }
 
         final Parent parent =
@@ -1318,14 +1367,17 @@
         final List<StylesheetContainer> sceneStylesheets =
                     gatherSceneStylesheets(scene);
 
-        boolean hasSceneStylesheets = sceneStylesheets.isEmpty() == false;
+        final boolean hasSceneStylesheets = sceneStylesheets.isEmpty() == false;
 
+        final String inlineStyle = node.getStyle();
+        final boolean hasInlineStyles = inlineStyle != null && inlineStyle.trim().isEmpty() == false;
         //
         // Are there any stylesheets at all?
         // If not, then there is nothing to match and the
         // resulting StyleMap is going to end up empty
         //
-        if (hasParentStylesheets == false
+        if (hasInlineStyles == false
+                && hasParentStylesheets == false
                 && hasSceneStylesheets == false
                 && userAgentStylesheets.isEmpty()) {
             return StyleMap.EMPTY_MAP;
@@ -1352,12 +1404,12 @@
         }
 
         Map<Key, Cache> cacheMap = cacheContainer.getCacheMap(parentStylesheets);
-
         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
@@ -1418,7 +1470,7 @@
         //
         // Create a style helper for this node from the styles that match.
         //
-        StyleMap smap = cache.getStyleMap(cacheContainer, node, triggerStates);
+        StyleMap smap = cache.getStyleMap(cacheContainer, node, triggerStates, hasInlineStyles);
 
         return smap;
     }
@@ -1551,12 +1603,65 @@
             }
         }
 
+        /**
+         * Get the mapping of property to style from Node.style for this node.
+         */
+        private Selector getInlineStyleSelector(String inlineStyle) {
+
+            // If there are no styles for this property then we can just bail
+            if ((inlineStyle == null) || inlineStyle.trim().isEmpty()) return null;
+
+            if (inlineStylesCache != null && inlineStylesCache.containsKey(inlineStyle)) {
+                // Value of Map entry may be null!
+                return inlineStylesCache.get(inlineStyle);
+            }
+
+            //
+            // inlineStyle wasn't in the inlineStylesCache, or inlineStylesCache was null
+            //
+
+            if (inlineStylesCache == null) {
+                inlineStylesCache = new HashMap<>();
+            }
+
+            final Stylesheet inlineStylesheet =
+                    CSSParser.getInstance().parse("*{"+inlineStyle+"}");
+
+            if (inlineStylesheet != null) {
+
+                inlineStylesheet.setOrigin(StyleOrigin.INLINE);
+
+                List<Rule> rules = inlineStylesheet.getRules();
+                Rule rule = rules != null && !rules.isEmpty() ? rules.get(0) : null;
+
+                List<Selector> selectors = rule != null ? rule.getUnobservedSelectorList() : null;
+                Selector selector = selectors != null && !selectors.isEmpty() ? selectors.get(0) : null;
+                selector.setOrdinal(-1);
+
+                inlineStylesCache.put(inlineStyle, selector);
+                return selector;
+
+            } else {
+
+                // even if inlineStylesheet is null, put it in cache so we don't
+                // bother with trying to parse it again.
+                inlineStylesCache.put(inlineStyle, null);
+                return null;
+            }
+        }
+
         private Map<StyleCache.Key,StyleCache> styleCache;
 
         private Map<List<String>, Map<Key,Cache>> cacheMap;
 
         private List<StyleMap> styleMapList;
 
+        /**
+         * Cache of parsed, inline styles. The key is Node.style.
+         * The value is the Selector from the inline stylesheet.
+         */
+        private Map<String,Selector> inlineStylesCache;
+
         /*
          * A simple counter used to generate a unique id for a StyleMap.
          * This unique id is used by StyleHelper in figuring out which
@@ -1579,15 +1684,23 @@
 
         private static class Key {
             final long[] key;
+            final String inlineStyle;
 
-            Key(long[] key) {
+            Key(long[] key, String inlineStyle) {
                 this.key = key;
+                // let inlineStyle be null if it is empty
+                this.inlineStyle =  (inlineStyle != null && inlineStyle.trim().isEmpty() ? null : inlineStyle);
+            }
+
+            @Override public String toString() {
+                return Arrays.toString(key) + (inlineStyle != null ? "* {" + inlineStyle + "}" : "");
             }
 
             @Override
             public int hashCode() {
                 int hash = 3;
-                hash = 97 * hash + Arrays.hashCode(this.key);
+                hash = 17 * hash + Arrays.hashCode(this.key);
+                if (inlineStyle != null) hash = 17 * hash + inlineStyle.hashCode();
                 return hash;
             }
 
@@ -1600,6 +1713,9 @@
                     return false;
                 }
                 final Key other = (Key) obj;
+                if (inlineStyle == null ? other.inlineStyle != null : !inlineStyle.equals(other.inlineStyle)) {
+                    return false;
+                }
                 if (!Arrays.equals(this.key, other.key)) {
                     return false;
                 }
@@ -1621,9 +1737,9 @@
             this.cache = new HashMap<Key, Integer>();
         }
 
-        private StyleMap getStyleMap(CacheContainer cacheContainer, Node node, Set<PseudoClass>[] triggerStates) {
+        private StyleMap getStyleMap(CacheContainer cacheContainer, Node node, Set<PseudoClass>[] triggerStates, boolean hasInlineStyle) {
 
-            if (selectors == null || selectors.isEmpty()) {
+            if ((selectors == null || selectors.isEmpty()) && !hasInlineStyle) {
                 return StyleMap.EMPTY_MAP;
             }
 
@@ -1640,7 +1756,7 @@
             // where the selectors that match this particular node are
             // represented by bits on the long[].
             //
-            long key[] = new long[Long.SIZE/selectorDataSize + 1];
+            long key[] = new long[selectorDataSize/Long.SIZE + 1];
             boolean nothingMatched = true;
 
             for (int s = 0; s < selectorDataSize; s++) {
@@ -1674,19 +1790,28 @@
             }
 
             // nothing matched!
-            if (nothingMatched) {
+            if (nothingMatched && hasInlineStyle == false) {
                 return StyleMap.EMPTY_MAP;
             }
 
-            final Key keyObj = new Key(key);
+            final String inlineStyle = node.getStyle();
+            final Key keyObj = new Key(key, inlineStyle);
+
             if (cache.containsKey(keyObj)) {
-                Integer id = cache.get(keyObj);
-                final StyleMap styleMap = id != null ? cacheContainer.getStyleMap(id.intValue()) : null;
+                Integer styleMapId = cache.get(keyObj);
+                final StyleMap styleMap = styleMapId != null
+                        ? cacheContainer.getStyleMap(styleMapId.intValue())
+                        : StyleMap.EMPTY_MAP;
                 return styleMap;
             }
 
             final List<Selector> selectors = new ArrayList<>();
 
+            if (hasInlineStyle) {
+                Selector selector = cacheContainer.getInlineStyleSelector(inlineStyle);
+                if (selector != null) selectors.add(selector);
+            }
+
             for (int k = 0; k<key.length; k++) {
 
                 if (key[k] == 0) continue;
@@ -1704,10 +1829,11 @@
                 }
             }
 
-            final int id = cacheContainer.nextSmapId();
+            int id = cacheContainer.nextSmapId();
+            cache.put(keyObj, Integer.valueOf(id));
+
             final StyleMap styleMap = new StyleMap(id, selectors);
             cacheContainer.addStyleMap(styleMap);
-            cache.put(keyObj, Integer.valueOf(id));
             return styleMap;
         }
 
--- a/javafx-ui-common/src/javafx/scene/CssStyleHelper.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/javafx/scene/CssStyleHelper.java	Wed Jun 12 16:32:53 2013 -0400
@@ -27,6 +27,7 @@
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -47,7 +48,6 @@
 import javafx.scene.text.Font;
 import javafx.scene.text.FontPosture;
 import javafx.scene.text.FontWeight;
-import javafx.stage.Window;
 import com.sun.javafx.Logging;
 import com.sun.javafx.Utils;
 import com.sun.javafx.css.CalculatedValue;
@@ -122,31 +122,25 @@
 
         if (styleMap == null || styleMap.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();
 
-                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 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;
+                }
+            }
 
-                    final CssMetaData<? extends Styleable, ?> prop = props.get(p);
-                    if (prop.isInherits()) {
-                        mightInherit = true;
-                        break;
-                    }
-                }
-
-                if (mightInherit == false) {
-                    return null;
-                }
+            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
@@ -220,20 +214,7 @@
 
             }
 
-            this.localStyleCache = new StyleCache();
-
-            final Map<StyleCache.Key,StyleCache> styleCache =
-                    StyleManager.getInstance().getStyleCache(node.getScene());
-
-            final StyleCache.Key styleCacheKey = new StyleCache.Key(smapIds, ctr);
-            StyleCache sharedCache = styleCache.get(styleCacheKey);
-
-            if (sharedCache == null) {
-                sharedCache = new StyleCache();
-                styleCache.put(styleCacheKey, sharedCache);
-            }
-
-            this.sharedCacheRef = new WeakReference<StyleCache>(sharedCache);
+            this.styleCacheKey = new StyleCache.Key(smapIds, ctr);
 
             CssMetaData<Styleable,Font> styleableFontProperty = null;
 
@@ -250,135 +231,51 @@
             }
 
             this.fontProp = styleableFontProperty;
+            this.fontSizeCache = new HashMap<>();
 
             this.cssSetProperties = new HashMap<String,StyleableProperty>();
 
         }
 
         private StyleMap getStyleMap(Styleable styleable) {
-            Scene scene = null;
-            if (styleable instanceof Node) {
-                scene = ((Node)styleable).getScene();
-            } else if (styleable instanceof Window) {
-                // this catches the PopupWindow case
-                scene = ((Window)styleable).getScene();
-            }
-            // todo: what other Styleables need to be handled here?
-
-            if (scene != null) {
-                return StyleManager.getInstance().getStyleMap(scene, smapId);
+            if (styleable != null) {
+                return StyleManager.getInstance().getStyleMap(styleable, smapId);
             } else {
                 return StyleMap.EMPTY_MAP;
             }
 
         }
 
+        // This is the key we use to find the shared cache
+        private final StyleCache.Key styleCacheKey;
+
+        // If the node has a fontProperty, we hang onto the CssMetaData for it
+        // so we can get at it later.
+        // TBD - why not the fontProperty itself?
         private final CssMetaData<Styleable,Font> fontProp;
+
+        // The id of StyleMap that contains the styles that apply to this node
         private final int smapId;
-        private final StyleCache localStyleCache;
-        private final Reference<StyleCache> sharedCacheRef;
+
+        // All nodes with the same set of styles share the same cache of
+        // calculated values. But one node might have a different font-size
+        // than another so the values are stored in cache by font-size.
+        // This map associates a style cache entry with the font to use when
+        // getting a value from or putting a value into cache.
+        private final Map<StyleCacheEntry.Key, CalculatedValue> fontSizeCache;
+
+        // Any properties that have been set by this style helper are tracked
+        // here so the property can be reset without expanding properties that
+        // were not set by css.
         private Map<String, StyleableProperty> cssSetProperties;
     }
 
-    //
-    // 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.Key getStyleCacheEntryKey(Node node, Set<PseudoClass>[] transitionStates) {
+    private void resetToInitialValues(Styleable styleable) {
 
-        if (cacheContainer == null) return null;
+        if (cacheContainer == null ||
+                cacheContainer.cssSetProperties == null ||
+                cacheContainer.cssSetProperties.isEmpty()) return;
 
-        //
-        // 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]
-        //
-        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);
-
-        return key;
-
-    }
-
-    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 (cacheContainer != null) {
-
-            cacheContainer.localStyleCache.clear();
-
-            // do we have any styles at all now?
-            final String inlineStyle = node.getStyle();
-            if(inlineStyle == null || inlineStyle.isEmpty()) {
-
-                StyleMap smap = getStyleMap(node);
-                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.
-                    cacheContainer = null;
-                    resetToInitialValues(node);
-                }
-
-                // 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 {
-            // if cacheContainer was null
-            final String inlineStyle = node.getStyle();
-            if (inlineStyle == null || inlineStyle.isEmpty()) {
-                return;
-            }
-            // if we don't have a cacheContainer, 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 cacheContainer.
-            // 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();
-            }
-
-            cacheContainer = new CacheContainer(node, StyleMap.EMPTY_MAP, depth);
-        }
-
-    }
-
-    private void resetToInitialValues(Styleable styleable) {
         for (StyleableProperty styleableProperty : cacheContainer.cssSetProperties.values()) {
             final StyleOrigin origin = styleableProperty.getStyleOrigin();
             if (origin != null && origin != StyleOrigin.USER) {
@@ -406,76 +303,6 @@
     }
 
     /**
-     * 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.getUnobservedDeclarationList();
-                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:
@@ -504,41 +331,66 @@
     }
 
     /**
-     * dynamic pseudo-class state of the node and its parents.
+     * 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.
-     *
+     * The StyleCacheEntry to choose depends on the Node's pseudo-class state
+     * and the pseudo-class state of its parents. Without the parent
+     * pseudo-class state, the fact that the the node in this pseudo-class state
+     * matched foo:blah bar { } is lost.
      */
+    // TODO: this should work on Styleable, not Node
     private Set<PseudoClass>[] getTransitionStates(Node node) {
 
+        // if cacheContainer is null, then CSS just doesn't apply to this node
+        if (cacheContainer == null) return null;
+
+        int depth = 0;
+        Node parent = node;
+        while (parent != null) {
+            depth += 1;
+            parent = parent.getParent();
+        }
+
+        //
+        // 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]
+        //
+        final Set<PseudoClass>[] retainedStates = new PseudoClassState[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
+        // retainedStates[0] is the pseudo-class state for node and
+        // retainedStates[1..(states.length-1)] are the retainedStates for the
         // node's parents.
         //
 
         int count = 0;
-        Node parent = node;
+        parent = node;
         while (parent != null) {
-            count += 1;
+            final CssStyleHelper helper = (parent instanceof Node) ? ((Node)parent).styleHelper : null;
+            if (helper != null) {
+                final Set<PseudoClass> pseudoClassState = ((Node)parent).pseudoClassStates;
+                retainedStates[count] = new PseudoClassState();
+                retainedStates[count].addAll(pseudoClassState);
+                // retainAll method takes the intersection of pseudoClassState and helper.triggerStates
+                retainedStates[count].retainAll(helper.triggerStates);
+                count += 1;
+            }
             parent = parent.getParent();
         }
 
-        Set<PseudoClass>[] states = new PseudoClassState[count];
+        final Set<PseudoClass>[] transitionStates = new PseudoClassState[count];
+        System.arraycopy(retainedStates, 0, transitionStates, 0, count);
 
-        count = 0;
-        parent = node;
-        while (parent != null) {
-            states[count] = parent.pseudoClassStates;
-            count += 1;
-            parent = parent.getParent();
-        }
-
-        return states;
+        return transitionStates;
 
     }
 
@@ -559,7 +411,6 @@
          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
@@ -575,83 +426,52 @@
             return;
         }
 
-        Set<PseudoClass>[] transitionStates = getTransitionStates(node);
-
         //
         // Styles that need lookup can be cached provided none of the styles
         // are from Node.style.
         //
-        StyleCacheEntry.Key cacheEntryKey = getStyleCacheEntryKey(node, transitionStates);
-        StyleCacheEntry cacheEntry = cacheContainer.localStyleCache.getStyleCacheEntry(cacheEntryKey);
+        final StyleCache sharedCache = StyleManager.getInstance().getSharedCache(node, cacheContainer.styleCacheKey);
 
-        boolean fastpath = cacheEntry != null;
-
-        if (cacheEntry == null) {
-
-            StyleCache sharedCache = cacheContainer.sharedCacheRef.get();
-            if (sharedCache != null) {
-
-                StyleCacheEntry sharedCacheEntry = sharedCache.getStyleCacheEntry(cacheEntryKey);
-                if (sharedCacheEntry == null) {
-                    sharedCacheEntry = new StyleCacheEntry();
-                    sharedCache.putStyleCacheEntry(cacheEntryKey, sharedCacheEntry);
-                }
-
-                cacheEntry = new StyleCacheEntry(sharedCacheEntry);
-                cacheContainer.localStyleCache.putStyleCacheEntry(cacheEntryKey, cacheEntry);
-
-            } else {
-                // Shared cache reference was null.
-                // This CssStyleHelper is, therefore, no good.
-                cacheContainer.localStyleCache.clear();
-                cacheContainer = 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 =
-                CssStyleHelper.getInlineStyleMap(node);
-
-        CalculatedValue fontForRelativeSizes = cacheEntry.getFont();
-
-        if (fontForRelativeSizes == null) {
-
-            fontForRelativeSizes =
-                getFontForUseInConvertingRelativeSize(
-                    node,
-                    cacheEntry,
-                    transitionStates[0],
-                    inlineStyles
-                );
-
-            cacheEntry.setFont(fontForRelativeSizes);
+        if (sharedCache == null) {
+            // Shared cache was blown away by StyleManager.
+            // Therefore, this CssStyleHelper is no good.
+            cacheContainer = null;
+            node.impl_reapplyCSS();
+            return;
 
         }
 
-        // origin of the font used for converting font-relative sizes
-        final StyleOrigin fontOrigin = fontForRelativeSizes.getOrigin();
+        final Set<PseudoClass>[] transitionStates = getTransitionStates(node);
 
-        fastpath =
-                fastpath &&
-                // 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.
-                fontOrigin != StyleOrigin.USER &&
-                // If the relative font came from an inline-style,
-                //   then we might not be able to use the value in shared cache.
-                fontOrigin != StyleOrigin.INLINE;
+        final StyleCacheEntry.Key fontCacheKey = new StyleCacheEntry.Key(transitionStates, Font.getDefault());
+        CalculatedValue cachedFont = cacheContainer.fontSizeCache.get(fontCacheKey);
 
-        final List<CssMetaData<? extends Styleable, ?>> styleables = node.getCssMetaData();
+        if (cachedFont == null) {
+
+            cachedFont = lookupFont(node, "-fx-font", true, null);
+
+            if (cachedFont == SKIP) cachedFont = getCachedFont(node.getStyleableParent());
+            if (cachedFont == null) cachedFont = new CalculatedValue(Font.getDefault(), null, false);
+
+            cacheContainer.fontSizeCache.put(fontCacheKey,cachedFont);
+
+        }
+
+        final Font fontForRelativeSizes = (Font)cachedFont.getValue();
+
+        final StyleCacheEntry.Key cacheEntryKey = new StyleCacheEntry.Key(transitionStates, fontForRelativeSizes);
+        StyleCacheEntry cacheEntry = sharedCache.getStyleCacheEntry(cacheEntryKey);
+
+        // if no one is watching for styles and the cacheEntry already exists,
+        // then we can definitely take the fastpath
+        final boolean fastpath = this.observableStyleMap == null && cacheEntry != null;
+
+        if (cacheEntry == null) {
+            cacheEntry = new StyleCacheEntry();
+            sharedCache.addStyleCacheEntry(cacheEntryKey, cacheEntry);
+        }
+
+        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();
@@ -687,23 +507,23 @@
                     ? new ArrayList<Style>()
                     : null;
 
-            CalculatedValue calculatedValue = null;
+            CalculatedValue calculatedValue = cacheEntry.get(property);
+            boolean addToCache = !fastpath && calculatedValue == null;
 
             if (fastpath) {
 
-                calculatedValue = cacheEntry.get(property);
-
-                // caclculatedValue may be null,
+                // calculatedValue may be null,
                 // but we should never put SKIP in cache.
                 if (calculatedValue == SKIP) {
                     assert false : "cache returned SKIP for " + property;
                     continue;
                 }
 
-            } else {
+            } else if (calculatedValue == null) {
 
-                calculatedValue = lookup(node, cssMetaData, node.pseudoClassStates,
-                        inlineStyles, node, fontForRelativeSizes, styleList);
+                // slowpath!
+                calculatedValue = lookup(node, cssMetaData, transitionStates[0],
+                        node, cachedFont, styleList);
 
                 // lookup is not supposed to return null.
                 if (calculatedValue == null) {
@@ -739,17 +559,15 @@
                     // there was no style for the property in the current
                     // state, so reset the property to its initial value.
                     if (styleableProperty != null) {
-
                         Object initial = cssMetaData.getInitialValue(node);
                         styleableProperty.applyStyle(null, initial);
-
                     }
 
                     continue;
 
                 }
 
-                if (fastpath == false) {
+                if (addToCache) {
 
                     // If we're not on the fastpath, then add the calculated
                     // value to cache.
@@ -801,7 +619,6 @@
                                 String.valueOf(value) + ", originOfCalculatedValue=" + originOfCalculatedValue);
                     }
 
-
                     styleableProperty.applyStyle(originOfCalculatedValue, value);
                 }
 
@@ -839,8 +656,6 @@
         // 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
     }
 
     /**
@@ -853,21 +668,19 @@
      * @param states
      * @return
      */
-    private CascadingStyle getStyle(Styleable styleable, String property, Set<PseudoClass> states, Map<String,CascadingStyle> inlineStyles){
-
-        final CascadingStyle inlineStyle = (inlineStyles != null) ? inlineStyles.get(property) : null;
+    private CascadingStyle getStyle(Styleable styleable, String property, Set<PseudoClass> states){
 
         // Get all of the Styles which may apply to this particular property
         final StyleMap smap = getStyleMap(styleable);
-        if (smap == null || smap.isEmpty()) return inlineStyle;
+        if (smap == null || smap.isEmpty()) return null;
 
         final Map<String, List<CascadingStyle>> cascadingStyleMap = smap.getCascadingStyles();
-        if (cascadingStyleMap == null || cascadingStyleMap.isEmpty()) return inlineStyle;
+        if (cascadingStyleMap == null || cascadingStyleMap.isEmpty()) return null;
 
         List<CascadingStyle> styles = cascadingStyleMap.get(property);
 
         // If there are no styles for this property then we can just bail
-        if ((styles == null) || styles.isEmpty()) return inlineStyle;
+        if ((styles == null) || styles.isEmpty()) return null;
 
         // Go looking for the style. We do this by visiting each CascadingStyle in
         // order finding the first that matches the current node & set of
@@ -886,14 +699,6 @@
             }
         }
 
-        if (inlineStyle != null) {
-
-            // is inlineStyle more specific than style?
-            if (style == null || inlineStyle.compareTo(style) < 0) {
-                style = inlineStyle;
-            }
-
-        }
         return style;
     }
 
@@ -908,21 +713,22 @@
      * @param states
      * @return
      */
-    private CalculatedValue lookup(Node node, CssMetaData styleable,
+    private CalculatedValue lookup(Node node,
+                                   CssMetaData styleable,
                                    Set<PseudoClass> states,
-                                   Map<String, CascadingStyle> userStyles, Node originatingNode,
-                                   CalculatedValue cachedFont, List<Style> styleList) {
+                                   Node originatingNode,
+                                   CalculatedValue cachedFont,
+                                   List<Style> styleList) {
 
         if (styleable.getConverter() == FontConverter.getInstance()) {
 
-            return lookupFont(node, styleable,
-                    originatingNode, cachedFont, styleList);
+            return lookupFont(node, styleable.getProperty(), false, styleList);
         }
 
         final String property = styleable.getProperty();
 
         // Get the CascadingStyle which may apply to this particular property
-        CascadingStyle style = getStyle(node, property, states, userStyles);
+        CascadingStyle style = getStyle(node, property, states);
 
         // 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
@@ -934,7 +740,7 @@
 
             if (numSubProperties == 0) {
 
-                return handleNoStyleFound(node, styleable, userStyles,
+                return handleNoStyleFound(node, styleable,
                         originatingNode, cachedFont, styleList);
 
             } else {
@@ -957,7 +763,7 @@
                 for (int i=0; i<numSubProperties; i++) {
                     CssMetaData subkey = subProperties.get(i);
                     CalculatedValue constituent =
-                        lookup(node, subkey, states, userStyles,
+                        lookup(node, subkey, states,
                             originatingNode, cachedFont, styleList);
                     if (constituent != SKIP) {
                         if (subs == null) {
@@ -981,7 +787,7 @@
 
                 // If there are no subkeys which apply...
                 if (subs == null || subs.isEmpty()) {
-                    return handleNoStyleFound(node, styleable, userStyles,
+                    return handleNoStyleFound(node, styleable,
                             originatingNode, cachedFont, styleList);
                 }
 
@@ -1031,8 +837,10 @@
             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, cachedFont, styleList);
+                style = getInheritedStyle(node, property);
+
+                if (style == null) return SKIP;
+
             }
         }
 
@@ -1044,21 +852,23 @@
             styleList.add(style.getStyle());
         }
 
-        return calculateValue(style, node, styleable, states, userStyles,
+        return calculateValue(style, node, styleable, states,
                 originatingNode, cachedFont, styleList);
     }
 
     /**
      * Called when there is no style found.
      */
-    private CalculatedValue handleNoStyleFound(Node node, CssMetaData styleable,
-                                               Map<String, CascadingStyle> userStyles,
-                                               Node originatingNode, CalculatedValue cachedFont, List<Style> styleList) {
+    private CalculatedValue handleNoStyleFound(Node node,
+                                               CssMetaData cssMetaData,
+                                               Node originatingNode,
+                                               CalculatedValue cachedFont,
+                                               List<Style> styleList) {
 
-        if (styleable.isInherits()) {
+        if (cssMetaData.isInherits()) {
 
 
-            StyleableProperty styleableProperty = styleable.getStyleableProperty(node);
+            StyleableProperty styleableProperty = cssMetaData.getStyleableProperty(node);
             StyleOrigin origin = styleableProperty != null ? styleableProperty.getStyleOrigin() : null;
 
             // RT-16308: if there is no matching style and the user set
@@ -1069,9 +879,13 @@
 
             }
 
+            CascadingStyle style = getInheritedStyle(node, cssMetaData.getProperty());
+            if (style == null) return SKIP;
+
             CalculatedValue cv =
-                inherit(node, styleable, userStyles,
-                    originatingNode, cachedFont, styleList);
+                    calculateValue(style, node, cssMetaData,
+                                   node.pseudoClassStates, originatingNode,
+                                   cachedFont, styleList );
 
             return cv;
 
@@ -1083,29 +897,40 @@
         }
     }
     /**
-     * Called when we must inherit a value from a parent node in the scenegraph.
+     * Called when we must getInheritedStyle a value from a parent node in the scenegraph.
      */
-    private CalculatedValue inherit(Node node, CssMetaData styleable,
-            Map<String,CascadingStyle> userStyles,
-            Node originatingNode, CalculatedValue cachedFont, List<Style> styleList) {
+    private CascadingStyle getInheritedStyle(
+            Node styleable,
+            String property) {
 
-        // Locate the first parentStyleHelper in the hierarchy
-        Node parent = node.getParent();
-        CssStyleHelper parentStyleHelper = parent == null ? null : parent.styleHelper;
-        while (parent != null && parentStyleHelper == null) {
+        Node parent = styleable != null ? styleable.getParent() : null;
+
+        while (parent != null) {
+
+            CssStyleHelper parentStyleHelper = parent.styleHelper;
+            if (parentStyleHelper != null) {
+
+                Set<PseudoClass> transitionStates = parent.pseudoClassStates;
+                CascadingStyle cascadingStyle = parentStyleHelper.getStyle(parent, property, transitionStates);
+
+                if (cascadingStyle != null) {
+
+                    final ParsedValueImpl cssValue = cascadingStyle.getParsedValueImpl();
+
+                    if ("inherit".equals(cssValue.getValue())) {
+                        return getInheritedStyle(parent, property);
+                    }
+                    return cascadingStyle;
+                }
+
+                return null;
+            }
+
             parent = parent.getParent();
-            if (parent != null) {
-                parentStyleHelper = parent.styleHelper;
-            }
+
         }
 
-        if (parent == null) {
-            return SKIP;
-        }
-
-        return parentStyleHelper.lookup(parent, styleable,
-                parent.pseudoClassStates,
-                getInlineStyleMap(parent), originatingNode, cachedFont, styleList);
+        return null;
     }
 
 
@@ -1115,10 +940,9 @@
     /**
      * Find the property among the styles that pertain to the Node
      */
-    private CascadingStyle resolveRef(Styleable styleable, String property, Set<PseudoClass> states,
-            Map<String,CascadingStyle> inlineStyles) {
+    private CascadingStyle resolveRef(Styleable styleable, String property, Set<PseudoClass> states) {
 
-        final CascadingStyle style = getStyle(styleable, property, states, inlineStyles);
+        final CascadingStyle style = getStyle(styleable, property, states);
         if (style != null) {
             return style;
         } else {
@@ -1127,7 +951,7 @@
             if (states != null && states.size() > 0) {
                 // if states > 0, then we need to check this node again,
                 // but without any states.
-                return resolveRef(styleable,property,NULL_PSEUDO_CLASS_STATE,inlineStyles);
+                return resolveRef(styleable,property,NULL_PSEUDO_CLASS_STATE);
             } else {
                 // TODO: This block was copied from inherit. Both should use same code somehow.
                 Styleable styleableParent = styleable.getStyleableParent();
@@ -1151,8 +975,7 @@
                         : styleable.getPseudoClassStates();
 
                 return parentStyleHelper.resolveRef(styleableParent, property,
-                        styleableParentPseudoClassStates,
-                        getInlineStyleMap(styleableParent));
+                        styleableParentPseudoClassStates);
             }
         }
     }
@@ -1162,7 +985,6 @@
             Styleable styleable,
             ParsedValueImpl parsedValue,
             Set<PseudoClass> states,
-            Map<String,CascadingStyle> inlineStyles,
             ObjectProperty<StyleOrigin> whence,
             List<Style> styleList) {
 
@@ -1180,7 +1002,7 @@
                 final String sval = (String)val;
 
                 CascadingStyle resolved =
-                    resolveRef(styleable, sval, states, inlineStyles);
+                    resolveRef(styleable, sval, states);
 
                 if (resolved != null) {
 
@@ -1206,7 +1028,7 @@
                     // 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(styleable, resolved.getParsedValueImpl(), states, inlineStyles, whence, styleList);
+                    return resolveLookups(styleable, resolved.getParsedValueImpl(), states, whence, styleList);
                 }
             }
         }
@@ -1224,7 +1046,7 @@
                 for (int ll=0; ll<layers[l].length; ll++) {
                     if (layers[l][ll] == null) continue;
                     layers[l][ll].setResolved(
-                        resolveLookups(styleable, layers[l][ll], states, inlineStyles, whence, styleList)
+                        resolveLookups(styleable, layers[l][ll], states, whence, styleList)
                     );
                 }
             }
@@ -1235,7 +1057,7 @@
             for (int l=0; l<layer.length; l++) {
                 if (layer[l] == null) continue;
                 layer[l].setResolved(
-                    resolveLookups(styleable, layer[l], states, inlineStyles, whence, styleList)
+                    resolveLookups(styleable, layer[l], states, whence, styleList)
                 );
             }
         }
@@ -1335,7 +1157,6 @@
             final Styleable node,
             final CssMetaData cssMetaData,
             final Set<PseudoClass> states,
-            final Map<String,CascadingStyle> inlineStyles,
             final Styleable originatingNode,
             final CalculatedValue fontFromCacheEntry,
             final List<Style> styleList) {
@@ -1345,12 +1166,19 @@
 
             ObjectProperty<StyleOrigin> whence = new SimpleObjectProperty<StyleOrigin>(style.getOrigin());
             final ParsedValueImpl resolved =
-                resolveLookups(node, cssValue, states, inlineStyles, whence, styleList);
+                resolveLookups(node, cssValue, states, whence, styleList);
 
             try {
+
+                final String property = cssMetaData.getProperty();
+
                 // The computed value
                 Object val = null;
-                Font fontForFontRelativeSizes = null;
+                boolean isFontProperty =
+                        "-fx-font".equals(property) ||
+                        "-fx-font-size".equals(property);
+
+                boolean isRelative = ParsedValueImpl.containsFontRelativeSize(resolved, isFontProperty);
 
                 //
                 // Avoid using a font calculated from a relative size
@@ -1366,11 +1194,10 @@
                 // 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() &&
-                    (fontFromCacheEntry == null || fontFromCacheEntry.isRelative()) &&
-                    ("-fx-font".equals(property) ||
-                     "-fx-font-size".equals(property)))  {
+                Font fontForFontRelativeSizes = null;
+
+                if (isRelative && isFontProperty &&
+                    (fontFromCacheEntry == null || fontFromCacheEntry.isRelative())) {
 
                     Styleable parent = node;
                     CalculatedValue childsCachedFont = fontFromCacheEntry;
@@ -1386,7 +1213,7 @@
                                 // If the cached fonts are the same, then the cached font came from the same
                                 // style and we need to keep looking. Otherwise, use the font we found.
                                 //
-                                if (parentsCachedFont.equals(childsCachedFont)) {
+                                if (childsCachedFont == null || parentsCachedFont.equals(childsCachedFont)) {
                                     childsCachedFont = parentsCachedFont;
                                 } else {
                                     fontForFontRelativeSizes = (Font)parentsCachedFont.getValue();
@@ -1419,7 +1246,7 @@
                     val = cssMetaData.getConverter().convert(resolved, fontForFontRelativeSizes);
 
                 final StyleOrigin origin = whence.get();
-                return new CalculatedValue(val, origin, resolved.isNeedsFont());
+                return new CalculatedValue(val, origin, isRelative);
 
             } catch (ClassCastException cce) {
                 final String msg = formatUnresolvedLookupMessage(node, cssMetaData, style.getStyle(),resolved);
@@ -1505,275 +1332,125 @@
         // there is a parent helper and a cacheContainer,
         } else  {
 
-            Set<PseudoClass>[] transitionStates = getTransitionStates(parent);
-            StyleCacheEntry.Key parentCacheEntryKey = parentHelper.getStyleCacheEntryKey(parent, transitionStates);
-            StyleCacheEntry parentCacheEntry = parentHelper.cacheContainer.localStyleCache.getStyleCacheEntry(parentCacheEntryKey);
+            CacheContainer parentCacheContainer = parentHelper.cacheContainer;
+            if ( parentCacheContainer != null
+                    && parentCacheContainer.fontSizeCache != null
+                    && parentCacheContainer.fontSizeCache.isEmpty() == false) {
 
-            if (parentCacheEntry != null) {
-
-                cachedFont = parentCacheEntry.getFont();
+                Set<PseudoClass>[] transitionStates = parentHelper.getTransitionStates(parent);
+                StyleCacheEntry.Key parentCacheEntryKey = new StyleCacheEntry.Key(transitionStates, Font.getDefault());
+                cachedFont = parentCacheContainer.fontSizeCache.get(parentCacheEntryKey);
 
             } else {
 
                 Set<PseudoClass> pseudoClassState = parent.getPseudoClassStates();
-                Map<String, CascadingStyle> inlineStyles = CssStyleHelper.getInlineStyleMap(styleable);
-                StyleCacheEntry tempEntry = new StyleCacheEntry();
-                cachedFont = parentHelper.getFontForUseInConvertingRelativeSize(styleable, tempEntry, pseudoClassState, inlineStyles);
+                cachedFont = parentHelper.lookup(parent, dummyFontProperty, pseudoClassState, parent, null, null);
             }
-
         }
 
         return cachedFont;
     }
 
-    private CalculatedValue getFontForUseInConvertingRelativeSize(
-             final Styleable styleable,
-             final StyleCacheEntry cacheEntry,
-             Set<PseudoClass> pseudoclassState,
-            Map<String,CascadingStyle> inlineStyles)
-     {
+    /*package access for testing*/ FontPosture getFontPosture(Font font) {
+        if (font == null) return FontPosture.REGULAR;
 
-        // 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;
+        String fontName = font.getName().toLowerCase();
 
-        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 (cacheContainer.fontProp != null) {
-            StyleableProperty<Font> styleableProp = cacheContainer.fontProp.getStyleableProperty(styleable);
-            StyleOrigin fpOrigin = styleableProp.getStyleOrigin();
-            if (fpOrigin == StyleOrigin.USER) {
-                origin = fpOrigin;
-                foundFont = styleableProp.getValue();
-            }
+        if (fontName.contains("italic")) {
+            return FontPosture.ITALIC;
         }
 
-        final CascadingStyle fontShorthand =
-            getStyle(styleable, "-fx-font", pseudoclassState, inlineStyles);
+        return FontPosture.REGULAR;
+    }
 
-        if (fontShorthand != null) {
+    /*package access for testing*/ FontWeight getFontWeight(Font font) {
+        if (font == null) return FontWeight.NORMAL;
 
-            final CalculatedValue cv =
-                calculateValue(fontShorthand, styleable, dummyFontProperty,
-                    pseudoclassState, inlineStyles,
-                    styleable, null, null);
+        String fontName = font.getName().toLowerCase();
 
-            // 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) {
+        if (fontName.contains("bold")) {
+            if (fontName.contains("extra")) return FontWeight.EXTRA_BOLD;
+            if (fontName.contains("ultra")) return FontWeight.EXTRA_BOLD;
+            else if (fontName.contains("semi")) return FontWeight.SEMI_BOLD;
+            else if (fontName.contains("demi")) return FontWeight.SEMI_BOLD;
+            else return FontWeight.BOLD;
 
-                // cv could be SKIP
-                if (cv.getValue() instanceof Font) {
-                    origin = cv.getOrigin();
-                    foundShorthand = cv;
-                    foundFont = null;
-                }
+        } else if (fontName.contains("light")) {
+            if (fontName.contains("extra")) return FontWeight.EXTRA_LIGHT;
+            if (fontName.contains("ultra")) return FontWeight.EXTRA_LIGHT;
+            else return FontWeight.LIGHT;
 
-            }
-         }
+        } else if (fontName.contains("black")) {
+            return FontWeight.BLACK;
 
-        final boolean isUserSet =
-                origin == StyleOrigin.USER || origin == StyleOrigin.INLINE;
+        } else if (fontName.contains("heavy")) {
+            return FontWeight.BLACK;
 
-        // 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(styleable, "-fx-font-size",
-                isUserSet, fontShorthand, 0, !CONSIDER_INLINE_STYLES);
-
-        if (fontSize != null) {
-
-            final CalculatedValue cv =
-                calculateValue(fontSize, styleable, dummyFontProperty, pseudoclassState, inlineStyles,
-                    styleable, null, 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) {
-
-                CalculatedValue cachedFont = getCachedFont(styleable.getStyleableParent());
-
-                if (cachedFont != null) {
-                    isRelative = cachedFont.isRelative();
-                }
-            }
-            return new CalculatedValue(foundFont, origin, isRelative);
-
-        } else {
-
-            // no font, font-size or fontProp.
-            // inherit by taking the parent's cache entry font.
-            CalculatedValue cachedFont = getCachedFont(styleable.getStyleableParent());
-
-            if (cachedFont != null) {
-                return cachedFont;
-            }
-        }
-        // last ditch effort -  take the default font.
-        return new CalculatedValue(Font.getDefault(), null, false);
-     }
-
-
-    private CascadingStyle lookupFontSubPropertyStyle(final Styleable styleable,
-            final String subProperty, final boolean isUserSet,
-            final CascadingStyle csShorthand,
-            final int distance,
-            boolean considerInlineStyles) {
-
-        Styleable parent = styleable;
-        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 instanceof Node ? ((Node)parent).pseudoClassStates : parent.getPseudoClassStates();
-            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.getStyleableParent();
-                nlooks += 1;
-                helper = parent instanceof Node ? ((Node)parent).styleHelper : null;
-            } while (parent != null && helper == null);
+        } else if (fontName.contains("medium")) {
+            return FontWeight.MEDIUM;
         }
 
-        if (csShorthand != null && returnValue != null) {
+        return FontWeight.NORMAL;
 
-            final boolean shorthandImportant =
-                    csShorthand.getStyle().getDeclaration().isImportant();
+    }
 
-            final Style style = returnValue.getStyle();
-            final boolean returnValueIsImportant =
-                style.getDeclaration().isImportant();
+    /*package access for testing*/ String getFontFamily(Font font) {
+        if (font == null) return Font.getDefault().getFamily();
+        return font.getFamily();
+    }
 
-            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;
+    /*package access for testing*/ Font deriveFont(
+            String fontFamily, FontWeight fontWeight, FontPosture fontPosture, double fontSize) {
 
-            }
+        return  Font.font(
+                Utils.stripQuotes(fontFamily),
+                fontWeight != FontWeight.NORMAL ? fontWeight : null,
+                fontPosture != FontPosture.REGULAR ? fontPosture : null,
+                fontSize);
+    }
 
-        }
+    /*package access for testing*/ Font deriveFont(Font font, String fontFamily) {
 
-        return returnValue;
+        if (font == null) return Font.getDefault();
 
+        FontPosture fontPosture = getFontPosture(font);
+        FontWeight fontWeight = getFontWeight(font);
+        double fontSize = font.getSize();
+
+        return deriveFont(fontFamily, fontWeight, fontPosture, fontSize);
+    }
+
+    /*package access for testing*/ Font deriveFont(Font font, double fontSize) {
+        if (font == null) return Font.getDefault();
+
+        String fontFamily = getFontFamily(font);
+        FontPosture fontPosture = getFontPosture(font);
+        FontWeight fontWeight = getFontWeight(font);
+
+        return deriveFont(fontFamily, fontWeight, fontPosture, fontSize);
+    }
+
+    /*package access for testing*/ Font deriveFont(Font font, FontPosture fontPosture) {
+
+        if (font == null) return Font.getDefault();
+
+        String fontFamily = getFontFamily(font);
+        FontWeight fontWeight = getFontWeight(font);
+        double fontSize = font.getSize();
+
+        return deriveFont(fontFamily, fontWeight, fontPosture, fontSize);
+    }
+
+    /*package access for testing*/ Font deriveFont(Font font, FontWeight fontWeight) {
+
+        if (font == null) return Font.getDefault();
+
+        String fontFamily = getFontFamily(font);
+        FontPosture fontPosture = getFontPosture(font);
+        double fontSize = font.getSize();
+
+        return deriveFont(fontFamily, fontWeight, fontPosture, fontSize);
     }
 
     /**
@@ -1789,278 +1466,272 @@
      * group.setStyle("-fx-font: 12px Arial;");
      * group.getChildren().add(text);
      * </pre>
-     *
-     * @param node
-     * @param styleable
-     * @param originatingNode
-     * @param fontFromCacheEntry
-     * @param styleList
-     * @return
      */
-    private CalculatedValue lookupFont(Styleable node, CssMetaData styleable,
-                                       Styleable originatingNode,
-                                       CalculatedValue fontFromCacheEntry, 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;
+     /*package access for testing*/ CalculatedValue lookupFont(
+            final Node styleable,
+            final String property,
+            boolean lookupForFontCache,
+            final List<Style> styleList)
+    {
 
         StyleOrigin origin = null;
-        boolean isRelative = false;
+        int distance = 0;
 
-        // 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;
+        // Each time a sub-property is encountered, cvFont is passed along to
+        // calculateValue and the resulting font becomes cvFont. In the end
+        // cvFont is returned.
+        CalculatedValue cvFont = null;
 
-        Styleable parent = node;
-        CssStyleHelper helper = this;
-        String property = styleable == null ? null : styleable.getProperty();
-        CascadingStyle csShorthand = null;
+        // Whether or not to look past the current node for inherited styles
+        // Will be false if the user set the font or there is a font-shorthand
+        boolean lookupInherited = true;
 
-        StyleableProperty styleableProperty = styleable.getStyleableProperty(node);
-        boolean isUserSet = styleableProperty.getStyleOrigin() == StyleOrigin.USER;
+        Set<PseudoClass> states = styleable.pseudoClassStates;
 
+        // 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.
 
-        while (parent != null) {
+        if (cacheContainer.fontProp != null) {
+            StyleableProperty<Font> styleableProp = cacheContainer.fontProp.getStyleableProperty(styleable);
+            StyleOrigin fpOrigin = styleableProp.getStyleOrigin();
+            if (fpOrigin == StyleOrigin.USER) {
+                origin = fpOrigin;
+                Font font = styleableProp.getValue();
+                cvFont = new CalculatedValue(font, origin, false);
+            }
+        }
 
-            final Set<PseudoClass> states = parent.getPseudoClassStates();
-            final Map<String,CascadingStyle> inlineStyles = CssStyleHelper.getInlineStyleMap(parent);
+        //
+        // Look up the font- properties
+        //
+        CascadingStyle fontShorthand = getStyle(styleable, property, states);
+        if (fontShorthand == null && lookupForFontCache == false) {
 
-            final CascadingStyle cascadingStyle =
-                helper.getStyle(parent, property, states, inlineStyles);
+            Node parent = styleable != null ? styleable.getParent() : null;
 
-            if (isUserSet) {
+            while (parent != null) {
 
-                //
-                // If current StyleOrigin is USER, then we don't look beyond the current node.
-                // Only if the user did not set the font will we inherit.
-                //
-                if (cascadingStyle != null) {
+                CssStyleHelper parentStyleHelper = parent.styleHelper;
+                if (parentStyleHelper != null) {
 
-                    origin = cascadingStyle.getOrigin();
+                    distance += 1;
 
-                    // 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;
+                    Set<PseudoClass> transitionStates = parent.pseudoClassStates;
+                    CascadingStyle cascadingStyle = parentStyleHelper.getStyle(parent, property, transitionStates);
+
+                    if (cascadingStyle != null) {
+
+                        final ParsedValueImpl cssValue = cascadingStyle.getParsedValueImpl();
+
+                        if ("inherit".equals(cssValue.getValue()) == false) {
+                            fontShorthand = cascadingStyle;
+                            break;
+                        }
                     }
 
                 }
 
-                break;
-
-            } else if (cascadingStyle != null) {
-                //
-                // If current StyleOrigin is not USER, 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 = origin == StyleOrigin.INLINE;
-                if (csShorthand == null || isInline) {
-                    origin = cascadingStyle.getOrigin();
-                    csShorthand = cascadingStyle;
-                    distance = nlooks;
-
-                    if (isInline) {
-                        break;
-                    }
-                }
-
+                parent = parent.getParent();
 
             }
 
-            //
-            // 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.getStyleableParent();
-                nlooks += 1;
-                helper = parent instanceof Node ? ((Node)parent).styleHelper : null;
-            } while (parent != null && helper == null);
-
         }
 
-        if (csShorthand == null) {
-            distance = nlooks;
+        // if user set the font, then fontShorthand must be at zero
+        if (fontShorthand != 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.
+            //
+            if (origin == null || origin.compareTo(fontShorthand.getOrigin()) <= 0) {
+
+                final CalculatedValue cv =
+                        calculateValue(fontShorthand, styleable, dummyFontProperty,
+                                       states, styleable, cvFont, styleList);
+
+                // cv could be SKIP
+                if (cv.getValue() instanceof Font) {
+                    origin = cv.getOrigin();
+                    cvFont = cv;
+                }
+
+            }
         }
-        nlooks = 0;
 
-        final Map<String,CascadingStyle> inlineStyles = getInlineStyleMap(node);
-        final Set<PseudoClass> states = node.getPseudoClassStates();
+        CascadingStyle fontSize = getStyle(styleable, property.concat("-size"), states);
+        if (fontSize == null && lookupForFontCache == false) {
+            fontSize = lookupInheritedFont(styleable, property.concat("-size"), distance);
+        }
 
-        String family = null;
-        double size = -1;
-        FontWeight weight = null;
-        FontPosture style = null;
+        // font-size must be closer and more specific than font shorthand
+        if (fontSize != null) {
 
-        if (csShorthand != null) {
+            if (origin == null || origin.compareTo(fontSize.getOrigin()) <= 0) {
 
-            if (styleList != null) {
-                styleList.add(csShorthand.getStyle());
-            }
+                final CalculatedValue cv =
+                        calculateValue(fontSize, styleable, dummyFontProperty,
+                                       states, styleable, cvFont, styleList);
 
-            // pull out the pieces.
-            final CalculatedValue cv =
-                calculateValue(csShorthand, node, styleable, states, inlineStyles,
-                    originatingNode, fontFromCacheEntry, 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();
+                if (cv.getValue() instanceof Double) {
                     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);
-
+                    if (cvFont != null) {
+                        boolean isRelative = cvFont.isRelative() || cv.isRelative();
+                        Font font = deriveFont((Font) cvFont.getValue(), ((Double) cv.getValue()).doubleValue());
+                        cvFont = new CalculatedValue(font, origin, isRelative);
+                    } else {
+                        boolean isRelative = cv.isRelative();
+                        Font font = deriveFont(Font.getDefault(), ((Double) cv.getValue()).doubleValue());
+                        cvFont = new CalculatedValue(font, origin, isRelative);
+                    }
                 }
             }
 
         }
 
-        CascadingStyle csFamily = null;
-        if ((csFamily = lookupFontSubPropertyStyle(node, property+"-family",
-                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES)) != null) {
+        if (lookupForFontCache == false ) {
 
-            if (styleList != null) {
-                styleList.add(csFamily.getStyle());
+            CascadingStyle fontWeight = getStyle(styleable, property.concat("-weight"), states);
+            if (fontWeight == null) {
+                fontWeight = lookupInheritedFont(styleable,property.concat("-weight"), distance);
             }
 
-            final CalculatedValue cv =
-                calculateValue(csFamily, node, styleable, states, inlineStyles,
-                    originatingNode, fontFromCacheEntry, styleList);
+            if (fontWeight != null) {
 
-            if (origin == null || origin.compareTo(cv.getOrigin()) <= 0) {
-                if (cv.getValue() instanceof String) {
-                    family = Utils.stripQuotes((String)cv.getValue());
-                    origin = cv.getOrigin();
+                if (origin == null || origin.compareTo(fontWeight.getOrigin()) <= 0) {
+
+                    final CalculatedValue cv =
+                            calculateValue(fontWeight, styleable, dummyFontProperty,
+                                           states, styleable, null, null);
+
+                    if (cv.getValue() instanceof FontWeight) {
+                        origin = cv.getOrigin();
+
+                        if (cvFont != null) {
+                            boolean isRelative = cvFont.isRelative();
+                            Font font = deriveFont((Font) cvFont.getValue(), (FontWeight) cv.getValue());
+                            cvFont = new CalculatedValue(font, origin, isRelative);
+                        } else {
+                            Font font = deriveFont(Font.getDefault(), (FontWeight) cv.getValue());
+                            cvFont = new CalculatedValue(font, origin, false);
+                        }
+                    }
                 }
+
             }
 
+            CascadingStyle fontStyle = getStyle(styleable, property.concat("-style"), states);
+            if (fontStyle == null) {
+                fontStyle = lookupInheritedFont(styleable, property.concat("-style"), distance);
+            }
+
+            if (fontStyle != null) {
+
+                if (origin == null || origin.compareTo(fontStyle.getOrigin()) <= 0) {
+
+                    final CalculatedValue cv =
+                            calculateValue(fontStyle, styleable, dummyFontProperty,
+                                           states, styleable, null, null);
+
+                    if (cv.getValue() instanceof FontPosture) {
+                        origin = cv.getOrigin();
+
+                        if (cvFont != null) {
+                            boolean isRelative = cvFont.isRelative();
+                            Font font = deriveFont((Font) cvFont.getValue(), (FontPosture) cv.getValue());
+                            cvFont = new CalculatedValue(font, origin, isRelative);
+                        } else {
+                            boolean isRelative = cv.isRelative();
+                            Font font = deriveFont(Font.getDefault(), (FontPosture) cv.getValue());
+                            cvFont = new CalculatedValue(font, origin, false);
+                        }
+                    }
+                }
+
+            }
+
+            CascadingStyle fontFamily = getStyle(styleable, property.concat("-family"), states);
+            if (fontFamily == null) {
+                fontFamily = lookupInheritedFont(styleable,property.concat("-family"), distance);
+            }
+
+            if (fontFamily != null) {
+
+                if (origin == null || origin.compareTo(fontFamily.getOrigin()) <= 0) {
+
+                    final CalculatedValue cv =
+                            calculateValue(fontFamily, styleable, dummyFontProperty,
+                                           states, styleable, null, null);
+
+                    if (cv.getValue() instanceof String) {
+                        origin = cv.getOrigin();
+
+                        if (cvFont != null) {
+                            boolean isRelative = cvFont.isRelative();
+                            Font font = deriveFont((Font) cvFont.getValue(), (String) cv.getValue());
+                            cvFont = new CalculatedValue(font, origin, isRelative);
+                        } else {
+                            Font font = deriveFont(Font.getDefault(), (String) cv.getValue());
+                            cvFont = new CalculatedValue(font, origin, false);
+                        }
+                    }
+                }
+
+            }
+        }
+
+        if (cvFont != null) {
+            return cvFont;
+
+        } else {
+            return SKIP;
+        }
+    }
+
+    /**
+     * Called when we must getInheritedStyle a value from a parent node in the scenegraph.
+     */
+    private CascadingStyle lookupInheritedFont(
+            Node styleable,
+            String property,
+            int distance) {
+
+        Node parent = styleable != null ? styleable.getParent() : null;
+
+        int nlooks = distance;
+        while (parent != null && nlooks >= 0) {
+
+            CssStyleHelper parentStyleHelper = parent.styleHelper;
+            if (parentStyleHelper != null) {
+
+                nlooks -= 1;
+
+                Set<PseudoClass> transitionStates = parent.pseudoClassStates;
+                CascadingStyle cascadingStyle = parentStyleHelper.getStyle(parent, property, transitionStates);
+
+                if (cascadingStyle != null) {
+
+                    final ParsedValueImpl cssValue = cascadingStyle.getParsedValueImpl();
+
+                    if ("inherit".equals(cssValue.getValue()) == false) {
+                        return cascadingStyle;
+                    }
+                }
+
+            }
+
+            parent = parent.getParent();
+
         }
 
-        CascadingStyle csSize = null;
-        if ((csSize = lookupFontSubPropertyStyle(node, property+"-size",
-                isUserSet, csShorthand, distance, CONSIDER_INLINE_STYLES))!= null) {
+        return null;
+    }
 
-            if (styleList != null) {
-                styleList.add(csSize.getStyle());
-            }
-
-            final CalculatedValue cv =
-                calculateValue(csSize, node, styleable, states, inlineStyles,
-                    originatingNode, fontFromCacheEntry, 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, fontFromCacheEntry, 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, fontFromCacheEntry, 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.
-        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
@@ -2097,41 +1768,6 @@
 
         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) ?
-                        ((Node)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();
             Node _node = node instanceof Node ? (Node)node : null;
             final Map<String, List<CascadingStyle>> smap = getCascadingStyles(_node);
@@ -2139,25 +1775,17 @@
 
              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);
+                    getMatchingLookupStyles(node, parsedValue, styleList);
                 }
             }
 
             if (styleableProperty.isInherits()) {
-                parent = node.getStyleableParent();
+                Styleable parent = node.getStyleableParent();
                 while (parent != null) {
                     CssStyleHelper parentHelper = parent instanceof Node
                             ? ((Node)parent).styleHelper
@@ -2174,7 +1802,7 @@
     }
 
     // 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) {
+    private void getMatchingLookupStyles(Styleable node, ParsedValueImpl parsedValue, List<CascadingStyle> styleList) {
 
         if (parsedValue.isLookup()) {
 
@@ -2205,19 +1833,11 @@
 
                         }
 
-                        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);
+                            getMatchingLookupStyles(parent, style.getParsedValueImpl(), styleList);
                         }
                     }
 
@@ -2238,7 +1858,7 @@
             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);
+                        getMatchingLookupStyles(node, layers[l][ll], styleList);
                 }
             }
 
@@ -2247,7 +1867,7 @@
             final ParsedValueImpl[] layer = (ParsedValueImpl[])val;
             for (int l=0; l<layer.length; l++) {
                 if (layer[l] == null) continue;
-                    getMatchingLookupStyles(node, layer[l], inlineStyleMap, styleList);
+                    getMatchingLookupStyles(node, layer[l], styleList);
             }
         }
 
--- a/javafx-ui-common/src/javafx/scene/Node.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Wed Jun 12 16:32:53 2013 -0400
@@ -8529,6 +8529,7 @@
             case CLEAN:
                 break;
             case DIRTY_BRANCH:
+            {
                 Parent me = (Parent)this;
                 // clear the flag first in case the flag is set to something
                 // other than clean by downstream processing.
@@ -8538,8 +8539,10 @@
                     children.get(i).processCSS();
                 }
                 break;
+            }
+            case RECALCULATE:
+                cssFlag = CssFlags.REAPPLY; // TODO
             case REAPPLY:
-            case RECALCULATE:
             case UPDATE:
             default:
                 impl_processCSS();
@@ -8619,18 +8622,11 @@
         } else if (cssFlag == CssFlags.RECALCULATE) {
 
             // Recalculate means that the in-line style has changed.
-            if (styleHelper != null) {
-                styleHelper.inlineStyleChanged(this);
-            } else {
-                // If there isn't a styleHelper now, there might need to be.
-                // Note that it is not necessary to REAPPLY css to children
-                // since the stylesheets haven't changed. The children only
-                // need to RECALCULATE their styles. A child that didn't
-                // have a styleHelper before will drop into this block, but if
-                // there are no matching style or inline styles, the child's
-                // styleHelper will still be null.
-                styleHelper = CssStyleHelper.createStyleHelper(this);
-            }
+
+            // Note: recalculate used to do something different than reapply,
+            // but the way calculated values are cached has changed.
+            // TODO: re-evalutate handling of CssFlags.RECALCULATE
+            styleHelper = CssStyleHelper.createStyleHelper(this);
 
         }
 
@@ -8640,7 +8636,7 @@
 
         // Transition to the new state and apply styles
         if (styleHelper != null) {
-            styleHelper.transitionToState(this);
+                styleHelper.transitionToState(this);
         }
     }
 
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/HonorDeveloperSettingsTest.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/HonorDeveloperSettingsTest.java	Wed Jun 12 16:32:53 2013 -0400
@@ -26,6 +26,9 @@
 package com.sun.javafx.css;
 
 import static org.junit.Assert.*;
+
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
 import javafx.scene.Cursor;
 import javafx.scene.Group;
 import javafx.scene.Scene;
@@ -36,8 +39,10 @@
 import javafx.stage.Stage;
 import javafx.stage.Window;
 
+import com.sun.javafx.Logging;
 import org.junit.Before;
 import org.junit.Test;
+import sun.util.logging.PlatformLogger;
 
 /**
  * AKA: RT-7401. Tests that the pattern used works by testing opacity
@@ -116,7 +121,7 @@
         assertEquals(.873, rect.getOpacity(), 0.01);
     }
 
-    @Test @org.junit.Ignore("fails, but works from an application")
+    @Test
     public void testOpacityWithManuallyChangedValueAndInlineStyleIsSetToInlineStyle() {
         rect.impl_processCSS(true);
         assertEquals(.76, rect.getOpacity(), 0.01);
@@ -257,7 +262,7 @@
         
     }
     
-    @Test @org.junit.Ignore("fails, but works from an application")
+    @Test
     public void testInlineStyleInheritedFromParentApplies() {
 
         // Must remove the id so we don't match on the ua style.
@@ -354,7 +359,7 @@
 
         // want text to get font style from .root
         // assuming here that test_FontInheritsFromDotRootStyle passed
-        text.setId(null);        
+        text.setId(null);
         text.setStyle("-fx-font-size: 24;");
 
         scene.getRoot().impl_processCSS(true);
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/LabeledText.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/LabeledText.java	Wed Jun 12 16:32:53 2013 -0400
@@ -273,8 +273,8 @@
             //    not override
             //
             if (propOrigin == null ||
-                    newOrigin == null ||
-                    propOrigin.compareTo(newOrigin) <= 0) {
+                   (newOrigin != null &&
+                    propOrigin.compareTo(newOrigin) <= 0)) {
                 super.applyStyle(newOrigin, value);
             }
         }
--- a/javafx-ui-controls/src/javafx/scene/control/Labeled.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-controls/src/javafx/scene/control/Labeled.java	Wed Jun 12 16:32:53 2013 -0400
@@ -734,6 +734,13 @@
     //     * externalization will work as expected
     //     */
 
+    @Override public String toString() {
+        StringBuilder builder =
+            new StringBuilder(super.toString())
+                .append("'").append(getText()).append("'");
+        return builder.toString();
+    }
+
     /***************************************************************************
      *                                                                         *
      * Stylesheet Handling                                                     *
--- a/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledTextTest.java	Wed Jun 12 18:45:49 2013 +0100
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledTextTest.java	Wed Jun 12 16:32:53 2013 -0400
@@ -73,7 +73,7 @@
     public void testLabeledTextAlignmentStyleAffectsLabeledText() {
         
         label.setStyle("-fx-text-alignment: right;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(TextAlignment.RIGHT, label.getTextAlignment());
         assertEquals(TextAlignment.RIGHT, labeledText.getTextAlignment());
     
@@ -93,7 +93,7 @@
     public void testLabeledFontStyleAffectsLabeledText() {
         
         label.setStyle("-fx-font: 10px Amble;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         Font expected = Font.font("Amble", 10);
         assertEquals(expected, label.getFont());
         assertEquals(expected, labeledText.getFont());
@@ -114,7 +114,7 @@
     public void testLabeledTextFillStyleAffectsLabeledText() {
         
         label.setStyle("-fx-text-fill: rgb(255,0,0);");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         Color expected = Color.rgb(255, 0, 0);
         assertEquals(expected, label.getTextFill());
         assertEquals(expected, labeledText.getFill());
@@ -135,7 +135,7 @@
     public void testLabeledUnderlineStyleAffectsLabeledText() {
         
         label.setStyle("-fx-underline: true;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assert(label.isUnderline() == true);
         assert(labeledText.isUnderline() == true);
     
@@ -144,7 +144,7 @@
     @Test
     public void testLabeledBlendModeStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-blend-mode: color-burn;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(BlendMode.COLOR_BURN,label.getBlendMode());
         assertFalse(BlendMode.COLOR_BURN.equals(labeledText.getBlendMode())); 
     }
@@ -152,7 +152,7 @@
     @Test
     public void testLabeledCursorStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-cursor: crosshair;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(Cursor.CROSSHAIR,label.getCursor());
         assertFalse(Cursor.CROSSHAIR.equals(labeledText.getCursor()));
     }
@@ -160,7 +160,7 @@
     @Test
     public void testLabeledEffectStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-effect: dropshadow(one-pass-box, red, 64, .5, 2, 3);");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertNotNull(label.getEffect());
         assertNull(labeledText.getEffect()); 
     }
@@ -168,7 +168,7 @@
     @Test
     public void testLabeledFocusTraversableStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-focus-traversable: true;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assert(label.focusTraversableProperty().get() == true);   
         assert(labeledText.focusTraversableProperty().get() == false);   
     }
@@ -176,7 +176,7 @@
     @Test
     public void testLabeledOpacityStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-opacity: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getOpacity(), .5, .0000001);   
         assertEquals(labeledText.getOpacity(), 1, .0000001);   
     }
@@ -184,7 +184,7 @@
     @Test
     public void testLabeledRotateStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-rotate: 180;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getRotate(), 180, .0000001);
         assertEquals(labeledText.getRotate(), 0, .0000001);   
     }
@@ -192,7 +192,7 @@
     @Test
     public void testLabeledScaleXStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-scale-x: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getScaleX(), .5, .0000001);
         assertEquals(labeledText.getScaleX(), 1, .0000001);   
     }
@@ -200,7 +200,7 @@
     @Test
     public void testLabeledScaleYStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-scale-y: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getScaleY(), .5, .0000001);
         assertEquals(labeledText.getScaleY(), 1, .0000001);   
     }
@@ -208,7 +208,7 @@
     @Test
     public void testLabeledScaleZStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-scale-z: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getScaleZ(), .5, .0000001);
         assertEquals(labeledText.getScaleZ(), 1, .0000001);   
     }
@@ -216,7 +216,7 @@
     @Test
     public void testLabeledTranslateXStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-translate-x: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getTranslateX(), .5, .0000001);
         assertEquals(labeledText.getTranslateX(), 0, .0000001);   
     }
@@ -224,7 +224,7 @@
     @Test
     public void testLabeledTranslateYStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-translate-y: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getTranslateY(), .5, .0000001);
         assertEquals(labeledText.getTranslateY(), 0, .0000001);   
     }
@@ -232,7 +232,7 @@
     @Test
     public void testLabeledTranslateZStyleDoesNotAffectLabeledText() {
         label.setStyle("-fx-translate-z: .5;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assertEquals(label.getTranslateZ(), .5, .0000001);
         assertEquals(labeledText.getTranslateZ(), 0, .0000001);   
     }
@@ -240,7 +240,7 @@
     @Test
     public void testLabeledVisibilityStyleDoesNotAffectLabeledText() {
         label.setStyle("visibility: false;");
-        label.impl_processCSS(false);
+        label.impl_processCSS(true);
         assert(label.visibleProperty().get() == false);   
         assert(labeledText.visibleProperty().get() == true);   
     }