changeset 1634:862dcc768d3a

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/2u/MASTER/jfx/rt
author kcr
date Tue, 18 Jun 2013 12:13:49 -0700
parents 061182f5d237 e40fc78d21fa
children 3baf54f57be7
files
diffstat 26 files changed, 643 insertions(+), 208 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Tue Jun 18 12:13:49 2013 -0700
@@ -334,14 +334,14 @@
         for (int n=0; n< relationships.size(); n++) os.writeByte(relationships.get(n).ordinal());
     }
 
-    public static CompoundSelector readBinary(final DataInputStream is, final String[] strings)
+    public static CompoundSelector readBinary(int version, final DataInputStream is, final String[] strings)
             throws IOException
     {
 
         final int nSelectors = is.readShort();
         final List<SimpleSelector> selectors = new ArrayList<SimpleSelector>();
         for (int n=0; n<nSelectors; n++) {
-            selectors.add((SimpleSelector)Selector.readBinary(is,strings));
+            selectors.add((SimpleSelector)Selector.readBinary(version, is,strings));
         }
 
         final int nRelationships = is.readShort();
--- a/javafx-ui-common/src/com/sun/javafx/css/Declaration.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Declaration.java	Tue Jun 18 12:13:49 2013 -0700
@@ -146,11 +146,11 @@
         os.writeBoolean(important);
     }
 
-    static Declaration readBinary(DataInputStream is, String[] strings)
+    static Declaration readBinary(int version, DataInputStream is, String[] strings)
         throws IOException
     {
         final String propertyName = strings[is.readShort()];
-        final ParsedValue parsedValue = ParsedValue.readBinary(is,strings);
+        final ParsedValue parsedValue = ParsedValue.readBinary(version, is,strings);
         final boolean important = is.readBoolean();
         return new Declaration(propertyName, parsedValue, important);
     }
--- a/javafx-ui-common/src/com/sun/javafx/css/ParsedValue.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/ParsedValue.java	Tue Jun 18 12:13:49 2013 -0700
@@ -585,22 +585,22 @@
             os.writeByte(NULL_VALUE);
 
         } else {
-            throw new InternalError("cannot writeBinary " + this);
+            throw new IllegalArgumentException("cannot writeBinary " + value);
         }
     }
 
-    public static ParsedValue readBinary(DataInputStream is, String[] strings)
+    public static ParsedValue readBinary(int version, DataInputStream is, String[] strings)
             throws IOException {
 
         final boolean lookup = is.readBoolean();
         final boolean hasType = is.readBoolean();
 
-        final StyleConverter converter = (hasType) ? StyleConverter.readBinary(is, strings) : null;
+        final StyleConverter converter = (hasType) ? StyleConverter.readBinary(version, is, strings) : null;
 
         final int valType = is.readByte();
 
         if (valType == VALUE) {
-            final ParsedValue value = ParsedValue.readBinary(is, strings);
+            final ParsedValue value = ParsedValue.readBinary(version, is, strings);
             return new ParsedValue(value, converter, lookup);
 
         } else if (valType == VALUE_ARRAY) {
@@ -609,7 +609,7 @@
             for (int v=0; v<nVals; v++) {
                 int vtype = is.readByte();
                 if (vtype == VALUE) {
-                    values[v] = ParsedValue.readBinary(is, strings);
+                    values[v] = ParsedValue.readBinary(version, is, strings);
                 } else {
                     values[v] = null;
                 }
@@ -625,7 +625,7 @@
                 for (int v=0; v<nVals; v++) {
                     int vtype = is.readByte();
                     if (vtype == VALUE) {
-                        layers[l][v] = ParsedValue.readBinary(is, strings);
+                        layers[l][v] = ParsedValue.readBinary(version, is, strings);
                     } else {
                         layers[l][v] = null;
                     }
@@ -644,6 +644,23 @@
             final int nameIndex = is.readShort();
             final String ename = strings[nameIndex];
             
+            if (version == 2) {
+                // RT-31022
+                // Once upon a time, the enum's class name was added to the 
+                // StringStore and the class name's index was written to the
+                // stream. Then the writeShort of the class name's index was 
+                // removed but the binary css version wasn't incremented. 
+                // So if we're trying to read a version 2 stream, then we'll
+                // read this short value. If the stream is actually a the 
+                // version without this short value, then the data will get 
+                // out of sync with the deserialization code and an exception
+                // will be thrown, at which point we can try a different 
+                // version.
+                // 
+                int bad = is.readShort();
+                if (bad >= strings.length) throw new IllegalArgumentException("bad version " + version);
+            }
+            
             ParsedValue value = new ParsedValue(ename, converter, lookup);
             return value;
 
@@ -674,14 +691,14 @@
                 URL url = new URL(str);
                 return new ParsedValue(url, converter, lookup);
             } catch (MalformedURLException malf) {
-                throw new InternalError("Excpeption in Value.readBinary: " + malf);
+                throw new IllegalArgumentException("Excpeption in Value.readBinary: " + malf);
             }
 
         } else if (valType == NULL_VALUE) {
             return new ParsedValue(null, converter, lookup);
 
         } else {
-            throw new InternalError("unknown type: " + valType);
+            throw new IllegalArgumentException("unknown type: " + valType);
         }
     }
 
--- a/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Tue Jun 18 12:13:49 2013 -0700
@@ -173,20 +173,20 @@
         }
     }
 
-    static Rule readBinary(DataInputStream is, String[] strings)
+    static Rule readBinary(int version, DataInputStream is, String[] strings)
             throws IOException
     {
         short nSelectors = is.readShort();
         List<Selector> selectors = new ArrayList<Selector>(nSelectors);
         for (int i = 0; i < nSelectors; i++) {
-            Selector s = Selector.readBinary(is, strings);
+            Selector s = Selector.readBinary(version, is, strings);
             selectors.add(s);
         }
 
         short nDeclarations = is.readShort();
         List<Declaration> declarations = new ArrayList<Declaration>(nDeclarations);
         for (int i = 0; i < nDeclarations; i++) {
-            Declaration d = Declaration.readBinary(is, strings);
+            Declaration d = Declaration.readBinary(version, is, strings);
             declarations.add(d);
         }
 
--- a/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Tue Jun 18 12:13:49 2013 -0700
@@ -104,13 +104,13 @@
         }
     }
 
-    static Selector readBinary(DataInputStream is, String[] strings)
+    static Selector readBinary(int version, DataInputStream is, String[] strings)
         throws IOException {
         final int type = is.readByte();
         if (type == TYPE_SIMPLE)
-            return SimpleSelector.readBinary(is,strings);
+            return SimpleSelector.readBinary(version, is,strings);
         else
-            return CompoundSelector.readBinary(is,strings);
+            return CompoundSelector.readBinary(version, is,strings);
     }
 
     public static Selector createSelector(final String cssSelector) {
--- a/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Tue Jun 18 12:13:49 2013 -0700
@@ -364,7 +364,7 @@
         for (String p : pseudoclasses)  os.writeShort(stringStore.addString(p));
     }
 
-    static SimpleSelector readBinary(final DataInputStream is, final String[] strings)
+    static SimpleSelector readBinary(int version, final DataInputStream is, final String[] strings)
         throws IOException
     {
         final String name = strings[is.readShort()];
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleConverter.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleConverter.java	Tue Jun 18 12:13:49 2013 -0700
@@ -92,7 +92,7 @@
     // map of StyleConverter class name to StyleConverter
     private static Map<String,StyleConverter> tmap;
 
-    public static StyleConverter readBinary(DataInputStream is, String[] strings)
+    public static StyleConverter readBinary(int version, DataInputStream is, String[] strings)
             throws IOException {
 
         int index = is.readShort();
@@ -101,7 +101,7 @@
         if (cname == null || cname.isEmpty()) return null;
         
         if (cname.startsWith("com.sun.javafx.css.converters.EnumConverter")) {
-            return com.sun.javafx.css.converters.EnumConverter.readBinary(is, strings);
+            return com.sun.javafx.css.converters.EnumConverter.readBinary(version, is, strings);
         } 
 
         // Make a new entry in tmap, if necessary
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Tue Jun 18 12:13:49 2013 -0700
@@ -1963,7 +1963,7 @@
                 calculateValue(csShorthand, node, styleable, states, inlineStyles, 
                     originatingNode, cacheEntry, styleList);
             
-            if (origin == null || origin.compareTo(cv.origin) <= 0) {
+            if (cv != SKIP && (origin == null || origin.compareTo(cv.origin) <= 0)) {
                 
                 if (cv.value instanceof Font) {
                     Font f = (Font)cv.value;
--- a/javafx-ui-common/src/com/sun/javafx/css/Stylesheet.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/Stylesheet.java	Tue Jun 18 12:13:49 2013 -0700
@@ -35,6 +35,8 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import javafx.collections.ListChangeListener.Change;
 import javafx.collections.ObservableList;
 
@@ -54,6 +56,8 @@
  */
 final public class Stylesheet {
 
+    public final static int BINARY_CSS_VERSION = 3;
+            
     public enum Origin {
         USER_AGENT,
         USER,
@@ -174,7 +178,7 @@
 
     // protected for unit testing 
     /** @treatAsPrivate public to allow unit testing */
-    public void readBinary(DataInputStream is, String[] strings)
+    public void readBinary(int version, DataInputStream is, String[] strings)
         throws IOException 
     {
         final int index = is.readShort();
@@ -182,7 +186,7 @@
         final int nRules = is.readShort();
         List<Rule> persistedRules = new ArrayList<Rule>(nRules);
         for (int n=0; n<nRules; n++) {
-            persistedRules.add(Rule.readBinary(is,strings));
+            persistedRules.add(Rule.readBinary(version,is,strings));
         }
         this.rules.addAll(persistedRules);
         
@@ -205,14 +209,35 @@
             dataInputStream = new DataInputStream(bufferedInputStream);
             // read file version
             final int version = dataInputStream.readShort();
-            if (version != 2)
-                throw new IOException(url.toString() + " wrong file version. got "
-                        + version + " expected 2");
+            if (version > Stylesheet.BINARY_CSS_VERSION) {
+                throw new IOException(url.toString() + " wrong binary CSS version: "
+                        + version + ". Expected version less than or equal to" +
+                        Stylesheet.BINARY_CSS_VERSION);
+            }
             // read strings
             final String[] strings = StringStore.readBinary(dataInputStream);
             // read binary data
             stylesheet = new Stylesheet(url);
-            stylesheet.readBinary(dataInputStream,strings);
+ 
+            // RT-31022
+            if (version == 2) {
+                boolean retry = false;
+                try {
+                    
+                    dataInputStream.mark(Integer.MAX_VALUE);
+                    stylesheet.readBinary(version, dataInputStream, strings);
+
+                } catch (Exception e) {
+                    
+                    stylesheet = new Stylesheet(url);
+
+                    dataInputStream.reset();
+                    stylesheet.readBinary(Stylesheet.BINARY_CSS_VERSION, dataInputStream, strings);
+
+                }
+            } else {
+                stylesheet.readBinary(Stylesheet.BINARY_CSS_VERSION, dataInputStream, strings);
+            }
 
         } catch (FileNotFoundException fnfe) {
             // This comes from url.openStream() and is expected. 
@@ -221,18 +246,12 @@
             // TODO: User logger here
             System.err.println(ignored);
             ignored.printStackTrace(System.err);
-        } finally {
+        } finally { 
             try {
-                if (dataInputStream != null) {
-                    dataInputStream.close();
-                } else if (bufferedInputStream != null) {
-                    bufferedInputStream.close();
-                } else if (inputStream != null) {
-                    inputStream.close();
-                }
-            } catch(IOException ioe) {
+                if (dataInputStream != null) dataInputStream.close();
+            } catch (IOException ignored) {
             }
-        }
+       }
 
         // return stylesheet
         return stylesheet;
--- a/javafx-ui-common/src/com/sun/javafx/css/converters/EnumConverter.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/converters/EnumConverter.java	Tue Jun 18 12:13:49 2013 -0700
@@ -77,7 +77,7 @@
         os.writeShort(index);
     }
     
-    public static StyleConverter readBinary(DataInputStream is, String[] strings)
+    public static StyleConverter readBinary(int version, DataInputStream is, String[] strings)
             throws IOException {
     
         short index = is.readShort();
--- a/javafx-ui-common/src/com/sun/javafx/css/converters/FontConverter.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/converters/FontConverter.java	Tue Jun 18 12:13:49 2013 -0700
@@ -125,7 +125,27 @@
         @Override
         public FontPosture convert(ParsedValue<FontUnits.Style, FontPosture> value, Font font) {
 
-            final FontUnits.Style style = value.getValue();
+            // Testing for RT-31022 exposed a ClassCastException where value 
+            // wraps a String (e.g., "ITALIC", not a FontUnits.Style). 
+            final Object val = value.getValue();
+            
+            FontUnits.Style style = null;
+            
+            if (val instanceof String) {
+                try {
+                    String sval = ((String)val).toUpperCase();
+                    style = Enum.valueOf(FontUnits.Style.class, sval); 
+                } catch (IllegalArgumentException iae) {
+                    return FontPosture.REGULAR;
+                } catch (NullPointerException npe) {
+                    return FontPosture.REGULAR;
+                }
+                
+            } else if (val instanceof FontUnits.Style) {
+                style = (FontUnits.Style)val;
+            } else {
+                return FontPosture.REGULAR;
+            }
 
             if (FontUnits.Style.INHERIT != style) {
                 return style.toFontPosture();
@@ -163,8 +183,26 @@
         @Override
         public FontWeight convert(ParsedValue<FontUnits.Weight, FontWeight> value, Font font) {
 
-            final FontUnits.Weight weight = value.getValue();
-
+            // Testing for RT-31022 exposed a ClassCastException where value 
+            // wraps a String (e.g., "BOLD", not a FontUnits.Weight). 
+            final Object val = value.getValue();
+            
+            FontUnits.Weight weight = null;
+            if (val instanceof String) {
+                try {
+                    String sval = ((String)val).toUpperCase();
+                    weight = Enum.valueOf(FontUnits.Weight.class, Utils.stripQuotes(sval));
+                } catch (IllegalArgumentException iae) {
+                    return FontWeight.NORMAL;
+                } catch (NullPointerException npe) {
+                    return FontWeight.NORMAL;
+                }
+            } else if (val instanceof FontUnits.Weight) {
+                weight = (FontUnits.Weight)val;
+            } else {
+                return FontWeight.NORMAL;
+            }
+            
             if (FontUnits.Weight.INHERIT != weight
                     && FontUnits.Weight.BOLDER != weight
                     && FontUnits.Weight.LIGHTER != weight) {
--- a/javafx-ui-common/src/com/sun/javafx/css/parser/Css2Bin.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/parser/Css2Bin.java	Tue Jun 18 12:13:49 2013 -0700
@@ -75,7 +75,7 @@
         FileOutputStream fos = new FileOutputStream(outFile);
         DataOutputStream os = new DataOutputStream(fos);
         // write file version
-        os.writeShort(2);
+        os.writeShort(Stylesheet.BINARY_CSS_VERSION);
         // write strings
         stringStore.writeBinary(os);
         // write binary data
--- a/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundImage.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundImage.java	Tue Jun 18 12:13:49 2013 -0700
@@ -24,7 +24,6 @@
  */
 package com.sun.javafx.scene.layout.region;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -37,6 +36,7 @@
 import com.sun.javafx.css.StyleableProperty;
 import com.sun.javafx.css.ParsedValue;
 import com.sun.javafx.css.converters.BooleanConverter;
+import com.sun.javafx.css.converters.EnumConverter;
 import com.sun.javafx.css.converters.URLConverter;
 import java.util.ArrayList;
 import javafx.beans.value.WritableValue;
@@ -495,9 +495,11 @@
         public static BackgroundRepeatConverter getInstance() {
             return Holder.BACKGROUND_REPEAT_CONVERTER;
         }
-
+        
+        private final EnumConverter<Repeat> converter;
         private BackgroundRepeatConverter() {
             super();
+            this.converter = new EnumConverter<Repeat>(Repeat.class);
         }
 
         @Override
@@ -506,8 +508,8 @@
             BackgroundRepeat[] backgroundRepeat = new BackgroundRepeat[layers.length];
             for (int l = 0; l < layers.length; l++) {
                 ParsedValue<String,Repeat>[] repeats = layers[l];
-                Repeat horizontal = repeats[0].convert(null);
-                Repeat vertical = repeats[1].convert(null);
+                Repeat horizontal = converter.convert(repeats[0], null);
+                Repeat vertical = converter.convert(repeats[1], null);
                 backgroundRepeat[l] = new BackgroundRepeat(horizontal,vertical);
             }
             return backgroundRepeat;
--- a/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImage.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImage.java	Tue Jun 18 12:13:49 2013 -0700
@@ -36,6 +36,7 @@
 import com.sun.javafx.css.StyleConverter;
 import com.sun.javafx.css.StyleableProperty;
 import com.sun.javafx.css.ParsedValue;
+import com.sun.javafx.css.converters.EnumConverter;
 import com.sun.javafx.css.converters.InsetsConverter;
 import com.sun.javafx.css.converters.URLConverter;
 import java.util.ArrayList;
@@ -431,8 +432,10 @@
             return Holder.BORDER_IMAGE_REPEAT_CONVERTER;
         }
 
+        private final EnumConverter<Repeat> repeatConverter;
         private RepeatConverter() {
             super();
+            repeatConverter = new EnumConverter<Repeat>(Repeat.class);
         }
 
         @Override
@@ -441,8 +444,8 @@
             BorderImageRepeat[] borderImageRepeats = new BorderImageRepeat[layers.length];
             for (int l = 0; l < layers.length; l++) {
                 ParsedValue<String,Repeat>[] repeats = layers[l];
-                Repeat horizontal = repeats[0].convert(null);
-                Repeat vertical = repeats[1].convert(null);
+                Repeat horizontal = repeatConverter.convert(repeats[0],null);
+                Repeat vertical = repeatConverter.convert(repeats[1],null);
                 borderImageRepeats[l] = new BorderImageRepeat(horizontal, vertical);
             }
             return borderImageRepeats;
--- a/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImageConverter.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImageConverter.java	Tue Jun 18 12:13:49 2013 -0700
@@ -46,9 +46,9 @@
         return Holder.BORDER_IMAGE_CONVERTER;
     }
 
-    private BorderImageConverter() {
+   private BorderImageConverter() {
         super();
-    }
+   }
 
     @Override
     public List<BorderImage> convert(Map<StyleableProperty, Object> convertedValues) {
--- a/javafx-ui-common/src/javafx/scene/Scene.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/javafx/scene/Scene.java	Tue Jun 18 12:13:49 2013 -0700
@@ -1902,23 +1902,6 @@
         }
 
         getKeyHandler().process(e);
-
-        // our little secret...
-        if (!e.isConsumed() && e.getCode() == KeyCode.DIGIT8 &&
-             e.getEventType() == KeyEvent.KEY_PRESSED && e.isControlDown() && e.isShiftDown()) {
-            try {
-                Class scenicview = Class.forName("com.javafx.experiments.scenicview.ScenicView");
-                Class params[] = new Class[1];
-                params[0] = Scene.class;
-                java.lang.reflect.Method method = scenicview.getDeclaredMethod("show", params);
-                method.invoke(null, this);
-
-            } catch (Exception ex) {
-                // oh well
-                //System.out.println("exception instantiating ScenicView:"+ex);
-
-            }
-        }
     }
 
     void requestFocus(Node node) {
--- a/javafx-ui-common/src/javafx/scene/layout/GridPane.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/src/javafx/scene/layout/GridPane.java	Tue Jun 18 12:13:49 2013 -0700
@@ -53,6 +53,7 @@
 import com.sun.javafx.css.converters.BooleanConverter;
 import com.sun.javafx.css.converters.EnumConverter;
 import com.sun.javafx.css.converters.SizeConverter;
+import java.util.Iterator;
 import javafx.collections.ListChangeListener;
 import javafx.geometry.Orientation;
 
@@ -593,7 +594,7 @@
             setConstraints(nodes[i], columnIndex, rowIndex + i);
         }
     }
-    
+
     static int getNodeRowIndex(Node node) {
         Integer rowIndex = getRowIndex(node);
         return rowIndex != null? rowIndex : 0;
@@ -926,7 +927,7 @@
                 int end = getNodeColumnEnd(child);
                 columnIndex = Math.max(columnIndex, (end != REMAINING? end : index) + 1);
             }
-        }        
+        }
         createRow(rowIndex, columnIndex, children);
         getChildren().addAll(children);
     }
@@ -951,7 +952,7 @@
                 int end = getNodeRowEnd(child);
                 rowIndex = Math.max(rowIndex, (end != REMAINING? end : index) + 1);
             }
-        }        
+        }
         createColumn(columnIndex, rowIndex, children);
         getChildren().addAll(children);
     }
@@ -983,7 +984,7 @@
     // This is set to true while in layoutChildren and set false on the conclusion.
     // It is used to decide whether to update metricsDirty in requestLayout().
     private boolean performingLayout = false;
-    
+
     @Override protected double computeMinWidth(double height) {
         computeGridMetrics();
         if (getContentBias() == Orientation.VERTICAL) {
@@ -1194,7 +1195,7 @@
             if (computeMin || computeMax || computePref || computeGrow || rowVPos == VPos.BASELINE) {
                 // compute from content
                 for (int j = 0; j < endNodes.size(); j++) {
-                    Node child = endNodes.get(j);                    
+                    Node child = endNodes.get(j);
                     Insets margin = getMargin(child);
                     double top = margin != null? margin.getTop() : 0;
                     int rowIndex = getNodeRowIndex(child);
@@ -1316,7 +1317,7 @@
                     columnPercentWidth[i] = constraints.getPercentWidth();
                     computeGrow = false;
                 } else {
-                    double w = constraints.getPrefWidth();          
+                    double w = constraints.getPrefWidth();
                     if (w != USE_COMPUTED_SIZE) {
                         columnPrefWidth[i] = w;
                         computePref = false;
@@ -1339,7 +1340,7 @@
             }
 
             if (computeMin || computeMax || computePref || computeGrow) {
-                // compute from content                
+                // compute from content
                 for (int j = 0; j < endNodes.size(); j++) {
                     Node child = endNodes.get(j);
                     Insets margin = getMargin(child);
@@ -1392,18 +1393,18 @@
 
             if (columnMinWidth[i] == USE_PREF_SIZE) {
                 //RT-20573 Use the bounded size if the pref has not been set
-                columnMinWidth[i] = columnPrefWidth[i] == 0 ? 
-                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ? 
-                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) : 
+                columnMinWidth[i] = columnPrefWidth[i] == 0 ?
+                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ?
+                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) :
                     columnPrefWidth[i];
             }
             if (columnMaxWidth[i] == USE_PREF_SIZE) {
-                columnMaxWidth[i] = columnPrefWidth[i] == 0 ? 
-                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ? 
-                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) : 
+                columnMaxWidth[i] = columnPrefWidth[i] == 0 ?
+                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ?
+                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) :
                     columnPrefWidth[i];
-            }                        
-            columnPrefWidth[i] = boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]);            
+            }
+            columnPrefWidth[i] = boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]);
             //System.out.println("column "+i+": h="+columnWidths[i]+" percent="+columnPercentWidth[i]+" min="+columnMinWidth[i]+" pref="+columnPrefWidth[i]+" max="+columnMaxWidth[i]+" grow="+columnGrow[i]);
         }
         // if percentages sum is bigger than 100, treat them as weights
@@ -1426,10 +1427,12 @@
     }
 
     double[] getColumnWidths() {
+        doLayout(false);
         return columnWidths;
     }
 
     double[] getRowHeights() {
+        doLayout(false);
         return rowHeights;
     }
 
@@ -1457,87 +1460,10 @@
         }
         super.requestLayout();
     }
-
+    
     @Override protected void layoutChildren() {
         performingLayout = true;
-        final double snaphgap = snapSpace(getHgap());
-        final double snapvgap = snapSpace(getVgap());
-        final double top = snapSpace(getInsets().getTop());
-        final double bottom = snapSpace(getInsets().getBottom());
-        final double left = snapSpace(getInsets().getLeft());
-        final double right = snapSpace(getInsets().getRight());
-
-        final double width = getWidth();
-        final double height = getHeight();
-        final double contentHeight = height - top - bottom;
-        final double contentWidth = width - left - right;
-        double columnTotal = 0;
-        double rowTotal = 0;
-        computeGridMetrics();
-
-        Orientation contentBias = getContentBias();        
-        if (contentBias == null) {
-            rowTotal = adjustRowHeights(rowPrefHeight, height);
-            columnTotal = adjustColumnWidths(columnPrefWidth, width);
-        } else if (contentBias == Orientation.HORIZONTAL) {
-            columnTotal = adjustColumnWidths(columnPrefWidth, width);
-            computeRowMetrics(rowHeights.length, columnWidths);
-            rowTotal = adjustRowHeights(rowPrefHeight, height);
-        } else if (contentBias == Orientation.VERTICAL) {
-            rowTotal = adjustRowHeights(rowPrefHeight, height);
-            computeColumnMetrics(columnWidths.length, rowHeights);
-            columnTotal = adjustColumnWidths(columnPrefWidth, width);
-        }
-
-        final double x = left + computeXOffset(contentWidth, columnTotal, getAlignment().getHpos());
-        final double y = top + computeYOffset(contentHeight, rowTotal, getAlignment().getVpos());
-        for (int i = 0; i < getChildren().size(); i++) {
-            Node child = getChildren().get(i);
-            if (child.isManaged()) {
-                int rowIndex = getNodeRowIndex(child);
-                int columnIndex = getNodeColumnIndex(child);
-                int colspan = getNodeColumnSpan(child);
-                if (colspan == REMAINING) {
-                    colspan = columnWidths.length - columnIndex;
-                }
-                int rowspan = getNodeRowSpan(child);
-                if (rowspan == REMAINING) {
-                    rowspan = rowHeights.length - rowIndex;
-                }
-                double areaX = x;
-                for (int j = 0; j < columnIndex; j++) {
-                    areaX += columnWidths[j] + snaphgap;
-                }
-                double areaY = y;
-                for (int j = 0; j < rowIndex; j++) {
-                    areaY += rowHeights[j] + snapvgap;
-                }
-                double areaW = columnWidths[columnIndex];
-                for (int j = 2; j <= colspan; j++) {
-                    areaW += columnWidths[columnIndex+j-1] + snaphgap;
-                }
-                double areaH = rowHeights[rowIndex];
-                for (int j = 2; j <= rowspan; j++) {
-                    areaH += rowHeights[rowIndex+j-1] + snapvgap;
-                }
-
-                HPos halign = getHalignment(child);
-                VPos valign = getValignment(child);
-                Insets margin = getMargin(child);
-                if (margin != null && valign == VPos.BASELINE) {
-                    // The top margin has already added to rowBaseline[] in computeRowMetric()
-                    // we do not need to add it again in layoutInArea.
-                    margin = new Insets(0, margin.getRight(), margin.getBottom(), margin.getLeft());
-                }
-                //System.out.println("layoutNode("+child.toString()+" row/span="+rowIndex+"/"+rowspan+" col/span="+columnIndex+"/"+colspan+" area="+areaX+","+areaY+" "+areaW+"x"+areaH+""+" rowBaseline="+rowBaseline[rowIndex]);
-                layoutInArea(child, areaX, areaY, areaW, areaH, rowBaseline[rowIndex],
-                        margin,
-                        shouldColumnFillWidth(columnIndex), shouldRowFillHeight(rowIndex),
-                        halign != null? halign : getColumnHalignment(columnIndex),
-                        valign != null? valign : getRowValignment(rowIndex));
-            }
-        }
-        layoutGridLines(x, y, rowTotal, columnTotal);
+        doLayout(true);
         performingLayout = false;
     }
 
@@ -1580,7 +1506,6 @@
     private double growOrShrinkRowHeights(Priority priority, double extraHeight) {
         final boolean shrinking = extraHeight < 0;
         List<Integer> adjusting = new ArrayList<Integer>();
-        List<Integer> adjusted = new ArrayList<Integer>();
 
         for (int i = 0; i < rowGrow.length; i++) {
             if (rowPercentHeight[i] < 0 && (shrinking || rowGrow[i] == priority)) {
@@ -1590,32 +1515,37 @@
 
         double available = extraHeight; // will be negative in shrinking case
         boolean handleRemainder = false;
-        int portion = 0;
-        while (available != 0 && adjusting.size() > 0) {
+        double portion = 0;
+
+        // RT-25684: We have to be careful that when subtracting change
+        // that we don't jump right past 0 - this leads to an infinite
+        // loop
+        final boolean wasPositive = available >= 0.0;
+        boolean isPositive = wasPositive;
+
+        double[] limitSize = shrinking? rowMinHeight : rowMaxHeight;
+        while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
             if (!handleRemainder) {
-                portion = (int)available / adjusting.size(); // negative in shrinking case
+                portion = available > 0 ? Math.floor(available / adjusting.size()) :
+                        Math.ceil(available / adjusting.size()); // negative in shrinking case
             }
             if (portion != 0) {
-                for (int i = 0; i < adjusting.size(); i++) {
-                    final int index = adjusting.get(i);
-                    final double limit = (shrinking? rowMinHeight[index] : rowMaxHeight[index])
+                for (Iterator<Integer> i = adjusting.iterator(); i.hasNext() && available != 0;) {
+                    final int index = i.next();
+                    final double limit = snapSpace(limitSize[index])
                             - rowHeights[index]; // negative in shrinking case
                     final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
-                    //System.out.println("row "+index+": height="+rowHeights[index]+" extra="+extraHeight+"portion="+portion+" row mpm="+rowMinHeight[index]+"/"+rowPrefHeight[index]+"/"+rowMaxHeight[index]+" limit="+limit+" change="+change);
-                    rowHeights[index] += change;                
+                    rowHeights[index] += change;
                     available -= change;
+                    isPositive = available >= 0.0;
                     if (Math.abs(change) < Math.abs(portion)) {
-                        adjusted.add(index);
+                        i.remove();
                     }
                     if (available == 0) {
                         break;
                     }
                 }
-                for (int i = 0; i < adjusted.size(); i++) {
-                    adjusting.remove(adjusted.get(i));
-                }
-                adjusted.clear();
-            } else {
+             } else {
                 // Handle the remainder
                 portion = (int)(available) % adjusting.size();
                 if (portion == 0) {
@@ -1627,10 +1557,7 @@
                 }
             }
         }
-                        
-        for (int i = 0; i < rowHeights.length; i++) {
-            rowHeights[i] = snapSpace(rowHeights[i]);            
-        }
+
         return available; // might be negative in shrinking case
     }
 
@@ -1672,44 +1599,51 @@
     }
 
     private double growOrShrinkColumnWidths(Priority priority, double extraWidth) {
+        if (extraWidth == 0) {
+            return 0;
+        }
         final boolean shrinking = extraWidth < 0;
-
         List<Integer> adjusting = new ArrayList<Integer>();
-        List<Integer> adjusted = new ArrayList<Integer>();
 
         for (int i = 0; i < columnGrow.length; i++) {
             if (columnPercentWidth[i] < 0 && (shrinking || columnGrow[i] == priority)) {
                 adjusting.add(i);
             }
         }
-        
+
         double available = extraWidth; // will be negative in shrinking case
         boolean handleRemainder = false;
-        int portion = 0;
-        while (available != 0 && adjusting.size() > 0) {            
+        double portion = 0;
+
+        // RT-25684: We have to be careful that when subtracting change
+        // that we don't jump right past 0 - this leads to an infinite
+        // loop
+        final boolean wasPositive = available >= 0.0;
+        boolean isPositive = wasPositive;
+
+        double[] limitSize = shrinking? columnMinWidth :
+                            columnMaxWidth;
+        while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
             if (!handleRemainder) {
-                portion = (int)available / adjusting.size(); // negative in shrinking case
+                portion = available > 0 ? Math.floor(available / adjusting.size()) :
+                        Math.ceil(available / adjusting.size()); // negative in shrinking case
             }
             if (portion != 0) {
-                for (int i = 0; i < adjusting.size(); i++) {
-                    final int index = adjusting.get(i);
-                    final double limit = (shrinking? columnMinWidth[index] : columnMaxWidth[index])
+                for (Iterator<Integer> i = adjusting.iterator(); i.hasNext() && available != 0;) {
+                    final int index = i.next();
+                    final double limit = snapSpace(limitSize[index])
                             - columnWidths[index]; // negative in shrinking case
                     final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
-                    columnWidths[index] += change;                
-                    //if (node.id.startsWith("debug.")) println("{if (shrinking) "vshrink" else "vgrow"}: {node.id} portion({portion})=available({available})/({sizeof adjusting}) change={change}");
+                    columnWidths[index] += change;
                     available -= change;
+                    isPositive = available >= 0.0;
                     if (Math.abs(change) < Math.abs(portion)) {
-                        adjusted.add(index);
+                        i.remove();
                     }
-                    if (available == 0) {                        
+                    if (available == 0) {
                         break;
-                    }                    
+                    }
                 }
-                for (int i = 0; i < adjusted.size(); i++) {
-                    adjusting.remove(adjusted.get(i));
-                }
-                adjusted.clear();
             } else {
                 // Handle the remainder
                 portion = (int)(available) % adjusting.size();
@@ -1722,10 +1656,7 @@
                 }
             }
         }
-               
-        for (int i = 0; i < columnWidths.length; i++) {
-            columnWidths[i] = snapSpace(columnWidths[i]);
-        }
+
         return available; // might be negative in shrinking case
     }
 
@@ -1786,6 +1717,89 @@
         return "Grid hgap="+getHgap()+", vgap="+getVgap()+", alignment="+getAlignment();
     }
 
+    private void doLayout(boolean withPositioning) {
+        final double snaphgap = snapSpace(getHgap());
+        final double snapvgap = snapSpace(getVgap());
+        final double top = snapSpace(getInsets().getTop());
+        final double bottom = snapSpace(getInsets().getBottom());
+        final double left = snapSpace(getInsets().getLeft());
+        final double right = snapSpace(getInsets().getRight());
+
+        final double width = getWidth();
+        final double height = getHeight();
+        final double contentHeight = height - top - bottom;
+        final double contentWidth = width - left - right;
+        double columnTotal = 0;
+        double rowTotal = 0;
+        computeGridMetrics();
+        
+        Orientation contentBias = getContentBias();
+        if (contentBias == null) {
+            rowTotal = adjustRowHeights(rowPrefHeight, height);
+            columnTotal = adjustColumnWidths(columnPrefWidth, width);
+        } else if (contentBias == Orientation.HORIZONTAL) {
+            columnTotal = adjustColumnWidths(columnPrefWidth, width);
+            computeRowMetrics(rowHeights.length, columnWidths);
+            rowTotal = adjustRowHeights(rowPrefHeight, height);
+        } else if (contentBias == Orientation.VERTICAL) {
+            rowTotal = adjustRowHeights(rowPrefHeight, height);
+            computeColumnMetrics(columnWidths.length, rowHeights);
+            columnTotal = adjustColumnWidths(columnPrefWidth, width);
+        }
+
+        if (withPositioning) {
+            final double x = left + computeXOffset(contentWidth, columnTotal, getAlignment().getHpos());
+            final double y = top + computeYOffset(contentHeight, rowTotal, getAlignment().getVpos());
+            for (int i = 0; i < getChildren().size(); i++) {
+                Node child = getChildren().get(i);
+                if (child.isManaged()) {
+                    int rowIndex = getNodeRowIndex(child);
+                    int columnIndex = getNodeColumnIndex(child);
+                    int colspan = getNodeColumnSpan(child);
+                    if (colspan == REMAINING) {
+                        colspan = columnWidths.length - columnIndex;
+                    }
+                    int rowspan = getNodeRowSpan(child);
+                    if (rowspan == REMAINING) {
+                        rowspan = rowHeights.length - rowIndex;
+                    }
+                    double areaX = x;
+                    for (int j = 0; j < columnIndex; j++) {
+                        areaX += columnWidths[j] + snaphgap;
+                    }
+                    double areaY = y;
+                    for (int j = 0; j < rowIndex; j++) {
+                        areaY += rowHeights[j] + snapvgap;
+                    }
+                    double areaW = columnWidths[columnIndex];
+                    for (int j = 2; j <= colspan; j++) {
+                        areaW += columnWidths[columnIndex+j-1] + snaphgap;
+                    }
+                    double areaH = rowHeights[rowIndex];
+                    for (int j = 2; j <= rowspan; j++) {
+                        areaH += rowHeights[rowIndex+j-1] + snapvgap;
+                    }
+
+                    HPos halign = getHalignment(child);
+                    VPos valign = getValignment(child);
+                    Insets margin = getMargin(child);
+                    if (margin != null && valign == VPos.BASELINE) {
+                        // The top margin has already added to rowBaseline[] in computeRowMetric()
+                        // we do not need to add it again in layoutInArea.
+                        margin = new Insets(0, margin.getRight(), margin.getBottom(), margin.getLeft());
+                    }
+                    //System.out.println("layoutNode("+child.toString()+" row/span="+rowIndex+"/"+rowspan+" col/span="+columnIndex+"/"+colspan+" area="+areaX+","+areaY+" "+areaW+"x"+areaH+""+" rowBaseline="+rowBaseline[rowIndex]);
+                    layoutInArea(child, areaX, areaY, areaW, areaH, rowBaseline[rowIndex],
+                            margin,
+                            shouldColumnFillWidth(columnIndex), shouldRowFillHeight(rowIndex),
+                            halign != null? halign : getColumnHalignment(columnIndex),
+                            valign != null? valign : getRowValignment(rowIndex));
+                }
+            }
+            layoutGridLines(x, y, rowTotal, columnTotal);
+        }
+    }
+
     /***************************************************************************
      *                                                                         *
      *                         Stylesheet Handling                             *
Binary file javafx-ui-common/test/unit/com/sun/javafx/css/RT-30953-2.2.21.bss has changed
Binary file javafx-ui-common/test/unit/com/sun/javafx/css/RT-30953-2.2.4.bss has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/RT-30953.css	Tue Jun 18 12:13:49 2013 -0700
@@ -0,0 +1,226 @@
+.root {
+    -fx-background-color: red;
+    -fx-background-color: red, yellow;
+    -fx-background-image: url("duke.png");
+    -fx-background-image: url("duke.png"), url("duke.png");
+    -fx-background-insets: 1px;
+    -fx-background-insets: 1px, 2px;
+    -fx-background-position: left;
+    -fx-background-position: right;
+    -fx-background-position: 10px;
+    -fx-background-position: 10px 20px;
+    -fx-background-position: left 20px;
+    -fx-background-position: 10px 20px, 20px 10px;
+    -fx-background-position: left 20px, right 20px;
+    -fx-background-radius: 1;
+    -fx-background-radius: 1 2;
+    -fx-background-radius: 1 2 3;
+    -fx-background-radius: 1 2 3 4;
+    -fx-background-radius: 1, 1;
+    -fx-background-radius: 1 2 3 4, 1 2 3 4;
+    -fx-background-insets: 1;
+    -fx-background-insets: 1 2;
+    -fx-background-insets: 1 2 3;
+    -fx-background-insets: 1 2 3 4;
+    -fx-background-insets: 1, 1;
+    -fx-background-insets: 1 2 3 4, 1 2 3 4;    
+    -fx-background-repeat: repeat-x;
+    -fx-background-repeat: repeat-y;
+    -fx-background-repeat: repeat;
+    -fx-background-repeat: space;
+    -fx-background-repeat: round;
+    -fx-background-repeat: stretch;
+    -fx-background-repeat: no-repeat;
+    -fx-background-repeat: repeat no-repeat;
+    -fx-background-repeat: repeat-x, repeat-y;
+    -fx-background-repeat: repeat no-repeat, round space;    
+    -fx-background-size: 100px;
+    -fx-background-size: 100px 100px;
+    -fx-background-size: auto;
+    -fx-background-size: cover;
+    -fx-background-size: contain;
+    -fx-background-size: stretch;
+    -fx-background-size: stretch, contain;        
+    -fx-border-color: red;
+    -fx-border-color: red yellow;
+    -fx-border-color: red yellow green;
+    -fx-border-color: red yellow green blue;
+    -fx-border-color: red, red;
+    -fx-border-color: red yellow green blue, red yellow green blue; 
+    -fx-border-radius: 1;
+    -fx-border-radius: 1 2;
+    -fx-border-radius: 1 2 3;
+    -fx-border-radius: 1 2 3 4;
+    -fx-border-radius: 1, 1;
+    -fx-border-radius: 1 2 3 4, 1 2 3 4;
+    -fx-border-insets: 1;
+    -fx-border-insets: 1 2;
+    -fx-border-insets: 1 2 3;
+    -fx-border-insets: 1 2 3 4;
+    -fx-border-insets: 1, 1;
+    -fx-border-insets: 1 2 3 4, 1 2 3 4;        
+   -fx-border-style: solid;
+    -fx-border-style: solid phase 10;
+    -fx-border-style: dotted;
+    -fx-border-style: dashed;
+    -fx-border-style: segments(1, 2, 3);
+    -fx-border-style: solid centered;
+    -fx-border-style: solid phase 10 centered;
+    -fx-border-style: solid inside;
+    -fx-border-style: solid outside;
+    -fx-border-style: solid line-join miter 10;
+    -fx-border-style: solid line-join bevel;
+    -fx-border-style: solid line-join round;
+    -fx-border-style: solid centered line-join miter 10;
+    -fx-border-style: solid centered line-join bevel;
+    -fx-border-style: solid phase 10 centered line-join miter 10;
+    -fx-border-style: solid phase 10 centered line-join bevel;
+    -fx-border-style: solid line-cap square;
+    -fx-border-style: solid line-cap butt;
+    -fx-border-style: solid line-cap round;
+    -fx-border-style: solid centered line-cap square;
+    -fx-border-style: solid centered line-cap butt;
+    -fx-border-style: solid phase 10 centered line-cap square;
+    -fx-border-style: solid phase 10 centered line-cap butt;
+    -fx-border-style: solid line-join miter 10 line-cap square;
+    -fx-border-style: solid line-join bevel line-cap square;
+    -fx-border-style: solid phase 10 line-join bevel line-cap square;
+    -fx-border-style: solid phase 10 line-join bevel line-cap square, dashed phase 10 line-join bevel line-cap square;
+    -fx-border-width: 1;
+    -fx-border-width: 1 2;
+    -fx-border-width: 1 2 3;
+    -fx-border-width: 1 2 3 4;
+    -fx-border-width: 1, 1;
+    -fx-border-width: 1 2 3 4, 1 2 3 4;        
+    -fx-border-image-insets: 1;
+    -fx-border-image-insets: 1 2;
+    -fx-border-image-insets: 1 2 3;
+    -fx-border-image-insets: 1 2 3 4;
+    -fx-border-image-insets: 1, 1;
+    -fx-border-image-insets: 1 2 3 4, 1 2 3 4;        
+    -fx-border-image-repeat: repeat-x;
+    -fx-border-image-repeat: repeat-y;
+    -fx-border-image-repeat: repeat;
+    -fx-border-image-repeat: space;
+    -fx-border-image-repeat: round;
+    -fx-border-image-repeat: stretch;
+    -fx-border-image-repeat: no-repeat;
+    -fx-border-image-repeat: repeat no-repeat;
+    -fx-border-image-repeat: repeat-x, repeat-y;
+    -fx-border-image-repeat: repeat no-repeat, round space;     
+    -fx-border-image-slice: 10%;
+    -fx-border-image-slice: 10% fill;
+    -fx-border-image-slice: 10% 10%;
+    -fx-border-image-slice: 10% 10% 10%;
+    -fx-border-image-slice: 10% 10% 10% fill;
+    -fx-border-image-slice: 10% 10% 10% 10%;
+    -fx-border-image-slice: 10% 10% 10% 10% fill;
+    -fx-border-image-slice: 10%, 10%;
+    -fx-border-image-slice: 10% fill, 10% fill;
+    -fx-border-image-slice: 10% 10% 10% 10% fill, 10% 10% 10% 10% fill;        
+    -fx-border-image-source: url("duke.png");
+    -fx-border-image-source: url("duke.png"), url("duke.png");
+    -fx-border-image-width: 1;
+    -fx-border-image-width: 1 2;
+    -fx-border-image-width: 1 2 3;
+    -fx-border-image-width: 1 2 3 4;
+    -fx-border-image-width: 1, 1;
+    -fx-border-image-width: 1 2 3 4, 1 2 3 4;        
+    -fx-padding: 1;
+    -fx-padding: 1 2;
+    -fx-padding: 1 2 3;
+    -fx-padding: 1 2 3 4;
+    -fx-padding: 1, 1;
+    -fx-padding: 1 2 3 4, 1 2 3 4;        
+    -fx-label-padding: 1;
+    -fx-label-padding: 1 2;
+    -fx-label-padding: 1 2 3;
+    -fx-label-padding: 1 2 3 4;
+    -fx-label-padding: 1, 1;
+    -fx-label-padding: 1 2 3 4, 1 2 3 4;        
+    -fx-shape: "M150 0 L75 200 L225 200 Z";
+    -fx-font-size: 18pt;
+    -fx-font-size: 1.5em;
+    -fx-font-size: 150%;
+    -fx-font-size: xx-small;
+    -fx-font-size: x-small;
+    -fx-font-size: small;
+    -fx-font-size: medium;
+    -fx-font-size: large;
+    -fx-font-size: x-large;
+    -fx-font-size: xx-large;
+    -fx-font-size: smaller;
+    -fx-font-size: larger;
+    -fx-font-style: italic;
+    -fx-font-weight: normal;
+    -fx-font-weight: bold;
+    -fx-font-weight: bolder;
+    -fx-font-weight: lighter;
+    -fx-font-weight: inherit;
+/*    -fx-font-weight: 100;
+    -fx-font-weight: 200;
+    -fx-font-weight: 300;
+    -fx-font-weight: 400;
+    -fx-font-weight: 500;
+    -fx-font-weight: 600;
+    -fx-font-weight: 700;
+    -fx-font-weight: 800;
+    -fx-font-weight: 900;*/
+    -fx-font: 16 "Comic Sans MS";
+    -fx-font: 16 Arial;
+    -fx-font: bold 16 Arial;
+    -fx-font: italic 16 Arial;
+    -fx-font: bold italic 16 Arial;
+    -fx-font: italic bold 16 Arial;
+    -fx-stroke-dash-array: 10 20 30 40;
+    -fx-stroke-line-join: miter 45;
+    -fx-stroke-line-join: bevel;
+    -fx-stroke-line-join: round;
+    -fx-stroke-line-cap: round;
+    -fx-stroke-line-cap: square;
+    -fx-stroke-line-cap: butt;
+    -fx-stroke-type: centered;
+    -fx-stroke-type: inside;
+    -fx-stroke-type: outside;
+    -fx-font-smoothing-type: gray;
+    -fx-font-smoothing-type: lcd;
+    -fx-text-alignment: left;
+    -fx-text-alignment: center;
+    -fx-text-alignment: right;
+    -fx-text-alignment: justify;
+    -fx-text-origin: top;
+    -fx-text-origin: baseline;
+    -fx-text-origin: bottom;
+    -fx-orientation: horizontal;
+    -fx-orientation: vertical;
+    -fx-alignment: top-left;
+    -fx-alignment: top-center;
+    -fx-alignment: top-right;
+    -fx-alignment: center-left;
+    -fx-alignment: center;
+    -fx-alignment: center-right;
+    -fx-alignment: bottom-left;
+    -fx-alignment: bottom-center;
+    -fx-alignment: bottom-right;
+    -fx-alignment: baseline-left;
+    -fx-alignment: baseline-center;
+    -fx-alignment: baseline-right;
+    -fx-text-overrun: center-ellipsis;
+    -fx-text-overrun: center-word-ellipsis;
+    -fx-text-overrun: clip;
+    -fx-text-overrun: ellipsis;
+    -fx-text-overrun: leading-ellipsis;
+    -fx-text-overrun: leading-word-ellipsis;
+    -fx-text-overrun: word-ellipsis;
+    -fx-content-display: top;
+    -fx-content-display: right;
+    -fx-content-display: bottom;
+    -fx-content-display: left;
+    -fx-content-display: center;
+    -fx-content-display: graphic-only;
+    -fx-content-display: text-only;
+    -fx-hbar-policy: never;
+    -fx-hbar-policy: always;
+    -fx-hbar-policy: as-needed;
+}
+    
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Tue Jun 18 12:13:49 2013 -0700
@@ -195,7 +195,7 @@
         DataInputStream is = null;
         String[] strings = null;
         Rule expResult = null;
-        Rule result = Rule.readBinary(is, strings);
+        Rule result = Rule.readBinary(Stylesheet.BINARY_CSS_VERSION,is, strings);
         assertEquals(expResult, result);
         fail("The test case is a prototype.");
     }
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/StyleConverterTest.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/StyleConverterTest.java	Tue Jun 18 12:13:49 2013 -0700
@@ -102,7 +102,7 @@
             byte[] b = new byte[]{0,0};                 
             ByteArrayInputStream bais = new ByteArrayInputStream(b); 
             DataInputStream dis = new DataInputStream(bais); 
-            StyleConverter ecv = StyleConverter.readBinary(dis,new String[]{"sun.invoke.util.Wrapper"}); 
+            StyleConverter ecv = StyleConverter.readBinary(Stylesheet.BINARY_CSS_VERSION,dis,new String[]{"sun.invoke.util.Wrapper"}); 
             assertNull(ecv);
         } catch(Exception e) {
             fail(e.getMessage());
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/StylesheetTest.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/StylesheetTest.java	Tue Jun 18 12:13:49 2013 -0700
@@ -25,12 +25,21 @@
 package com.sun.javafx.css;
 
 import com.sun.javafx.css.Stylesheet.Origin;
+import com.sun.javafx.css.converters.EnumConverter;
+import com.sun.javafx.css.converters.StringConverter;
+import com.sun.javafx.css.parser.CSSParser;
 import java.net.URL;
 import java.util.Collections;
 import java.util.List;
+import javafx.geometry.Orientation;
+import javafx.geometry.Pos;
+import javafx.geometry.VPos;
 import javafx.scene.Group;
 import javafx.scene.Scene;
 import javafx.scene.shape.Rectangle;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontSmoothingType;
+import javafx.scene.text.TextAlignment;
 import javafx.stage.Stage;
 import org.junit.*;
 import static org.junit.Assert.*;
@@ -218,5 +227,128 @@
         }
         
     }
+
+    @Test
+    public void testRT_30953_parse() {
+        
+        try {
+            // RT-30953-2.2.4_33.bss was generated with javafx version 2.2.4_33
+            URL url = StylesheetTest.class.getResource("RT-30953.css");
+            if (url == null) {
+                fail("Can't find RT-30953.css");
+            }
+            
+            Stylesheet ss = CSSParser.getInstance().parse(url);
+            checkConvert(ss);
+            
+       } catch (Exception e) {
+            fail(e.toString());
+        }
+        
+    }
+    
+    @Test
+    public void testRT_30953_deserialize_from_2_2_4() {
+        
+        // RT-30953-2.2.4bss was generated with javafx version 2.2.4 from 7u10
+        Stylesheet ss = deserialize("RT-30953-2.2.4.bss");
+        checkConvert(ss);
+    }
+
+    @Test
+    public void testRT_30953_deserialize_from_2_2_21() {
+        
+        // RT-30953-2.2.21.bss was generated with javafx version 2.2.21 from 7u21
+        Stylesheet ss = deserialize("RT-30953-2.2.21.bss");
+        checkConvert(ss);
+        
+    }
+    
+    private Stylesheet deserialize(String bssFile) {
+        Stylesheet ss = null;
+        try {
+            URL url = StylesheetTest.class.getResource(bssFile);
+            if (url == null) {
+                fail(bssFile);
+            }
+            ss = Stylesheet.loadBinary(url);
+        } catch (Exception e) {
+            fail(e.toString());
+        } finally {
+            return ss;
+        }
+    }
+    
+    private void checkConvert(Stylesheet ss) {
+        Declaration decl = null;
+        StyleConverter converter = null;
+        try {
+            for (Rule r : ss.getRules()) {
+                for (Declaration d : r.getDeclarations()) {
+                    decl = d;
+                    ParsedValue pv = decl.getParsedValue();
+                    converter = pv.getConverter();
+                    if (converter == null) {
+                        
+                        if ("inherit".equals(pv.getValue())) continue;
+                        
+                        String prop = d.getProperty().toLowerCase();
+                        if ("-fx-shape".equals(prop)) {
+                            StringConverter.getInstance().convert(pv, null);
+                        } else if ("-fx-font-smoothing-type".equals(prop)) {
+                            (new EnumConverter<FontSmoothingType>(FontSmoothingType.class)).convert(pv, null);
+                        } else if ("-fx-text-alignment".equals(prop)) {
+                            (new EnumConverter<TextAlignment>(TextAlignment.class)).convert(pv, null);
+                        } else if ("-fx-alignment".equals(prop)) {
+                            (new EnumConverter<Pos>(Pos.class)).convert(pv, null);
+                        } else if ("-fx-text-origin".equals(prop)) {
+                            (new EnumConverter<VPos>(VPos.class)).convert(pv, null);
+                        } else if ("-fx-text-overrun".equals(prop)) {
+                            Class cl = null;
+                            try {
+                                cl = Class.forName("javafx.scene.control.OverrunStyle");
+                            } catch (Exception ignored) {
+                                // just means we're running ant test from javafx-ui-common    
+                            }
+                            if (cl != null) {
+                                (new EnumConverter(cl)).convert(pv, null);
+                            }
+                        } else if ("-fx-orientation".equals(prop)) {
+                            (new EnumConverter<Orientation>(Orientation.class)).convert(pv, null);
+                        } else if ("-fx-content-display".equals(prop)) {
+                            Class cl = null;
+                            try {
+                                cl = Class.forName("javafx.scene.control.CpntentDisplay");
+                            } catch (Exception ignored) {
+                                // just means we're running ant test from javafx-ui-common    
+                            }
+                            if (cl != null) {
+                                (new EnumConverter(cl)).convert(pv, null);
+                            }
+                        } else if ("-fx-hbar-policy".equals(prop)) {
+                            Class cl = null;
+                            try {
+                                cl = Class.forName("javafx.scene.control.ScrollPane.ScrollBarPolicy");
+                            } catch (Exception ignored) {
+                                // just means we're running ant test from javafx-ui-common    
+                            }
+                            if (cl != null) {
+                                (new EnumConverter(cl)).convert(pv, null);
+                            }
+                        } else {
+                            System.out.println("No converter for " + d.toString() + ". Skipped conversion.");
+                        }
+                        continue;
+                    }
+                    Object value = converter.convert(pv, Font.getDefault());
+                }
+            }
+       } catch (Exception e) {
+            if (decl == null) fail(e.toString());
+            else if (converter != null) fail(decl.getProperty() + ", " + converter + ", " + e.toString());                
+            else fail(decl.getProperty() + ", " + e.toString());
+        }
+        
+    }
     
 }
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/converters/EnumConverterTest.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/converters/EnumConverterTest.java	Tue Jun 18 12:13:49 2013 -0700
@@ -8,6 +8,7 @@
 import com.sun.javafx.css.StringStore;
 import com.sun.javafx.css.StyleConverter;
 import com.sun.javafx.css.StyleableProperty;
+import com.sun.javafx.css.Stylesheet;
 import java.io.*;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -148,7 +149,7 @@
             byte[] b = new byte[]{0,0};                 
             ByteArrayInputStream bais = new ByteArrayInputStream(b); 
             DataInputStream dis = new DataInputStream(bais); 
-            StyleConverter ecv = EnumConverter.readBinary(dis,new String[]{"sun.invoke.util.Wrapper"}); 
+            StyleConverter ecv = EnumConverter.readBinary(Stylesheet.BINARY_CSS_VERSION,dis,new String[]{"sun.invoke.util.Wrapper"}); 
             // if assertions are off, then ecv will be null.
             assertNull(ecv);
         } catch (java.io.IOException ioe) {
@@ -192,7 +193,7 @@
         String[] strings = sstore.strings.toArray(new String[sstore.strings.size()]);
 //System.out.println(Arrays.toString(strings));
 //System.out.println(Arrays.toString(baos.toByteArray()));
-        StyleConverter actual = StyleConverter.readBinary(dis, strings);
+        StyleConverter actual = StyleConverter.readBinary(Stylesheet.BINARY_CSS_VERSION,dis, strings);
         
         assertEquals(expected, actual);
     }
Binary file javafx-ui-common/test/unit/com/sun/javafx/css/duke.png has changed
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/parser/CSSParserTest.java	Wed Jun 12 16:44:51 2013 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/parser/CSSParserTest.java	Tue Jun 18 12:13:49 2013 -0700
@@ -173,7 +173,7 @@
             DataInputStream dis = new DataInputStream(bais);
             
             Stylesheet restored = new Stylesheet();
-            restored.readBinary(dis, stringStore.strings.toArray(new String[stringStore.strings.size()]));
+            restored.readBinary(Stylesheet.BINARY_CSS_VERSION,dis, stringStore.strings.toArray(new String[stringStore.strings.size()]));
             
             List<Rule> cssRules = stylesheet.getRules();
             List<Rule> bssRules = restored.getRules();