changeset 1631:6a223e588b64

RT-31022: if an exception is raised when deserializing a version 2 .bss file, retry parsing as a version 3.
author David Grieve<david.grieve@oracle.com>
date Fri, 14 Jun 2013 16:01:29 -0400
parents e1b2ee95cb11
children e40fc78d21fa
files javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java javafx-ui-common/src/com/sun/javafx/css/Declaration.java javafx-ui-common/src/com/sun/javafx/css/ParsedValue.java javafx-ui-common/src/com/sun/javafx/css/Rule.java javafx-ui-common/src/com/sun/javafx/css/Selector.java javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java javafx-ui-common/src/com/sun/javafx/css/StyleConverter.java javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java javafx-ui-common/src/com/sun/javafx/css/Stylesheet.java javafx-ui-common/src/com/sun/javafx/css/converters/EnumConverter.java javafx-ui-common/src/com/sun/javafx/css/converters/FontConverter.java javafx-ui-common/src/com/sun/javafx/css/parser/Css2Bin.java javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundImage.java javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImage.java javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImageConverter.java javafx-ui-common/test/unit/com/sun/javafx/css/RT-30953-2.2.21.bss javafx-ui-common/test/unit/com/sun/javafx/css/RT-30953-2.2.4.bss javafx-ui-common/test/unit/com/sun/javafx/css/RT-30953.css javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java javafx-ui-common/test/unit/com/sun/javafx/css/StyleConverterTest.java javafx-ui-common/test/unit/com/sun/javafx/css/StylesheetTest.java javafx-ui-common/test/unit/com/sun/javafx/css/converters/EnumConverterTest.java javafx-ui-common/test/unit/com/sun/javafx/css/duke.png javafx-ui-common/test/unit/com/sun/javafx/css/parser/CSSParserTest.java
diffstat 24 files changed, 494 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/CompoundSelector.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/Declaration.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/ParsedValue.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/Rule.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/Selector.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleConverter.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/Stylesheet.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/converters/EnumConverter.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/converters/FontConverter.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/css/parser/Css2Bin.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundImage.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImage.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BorderImageConverter.java	Fri Jun 14 16:01:29 2013 -0400
@@ -46,9 +46,9 @@
         return Holder.BORDER_IMAGE_CONVERTER;
     }
 
-    private BorderImageConverter() {
+   private BorderImageConverter() {
         super();
-    }
+   }
 
     @Override
     public List<BorderImage> convert(Map<StyleableProperty, Object> convertedValues) {
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	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/RuleTest.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/StyleConverterTest.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/StylesheetTest.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/converters/EnumConverterTest.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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	Fri Jun 14 15:02:05 2013 +0100
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/parser/CSSParserTest.java	Fri Jun 14 16:01:29 2013 -0400
@@ -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();