changeset 1136:c555ea353dcf

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/2.2/MASTER/rt
author leifs
date Wed, 23 May 2012 16:09:59 -0700
parents 72bd9ac17500 dc5dd86e13ab
children 199012a5686d
files javafx-ui-common/src/javafx/scene/Scene.java javafx-ui-common/src/javafx/scene/doc-files/cssref.html
diffstat 26 files changed, 1149 insertions(+), 221 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-charts/src/javafx/scene/chart/XYChart.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/XYChart.java	Wed May 23 16:09:59 2012 -0700
@@ -613,7 +613,7 @@
 
     /** @inheritDoc */
     @Override protected final void layoutChartChildren(double top, double left, double width, double height) {
-        if(getData() == null) return;
+        if(getData() == null || height <= 0 || width <= 0 ) return;
         if (!rangeValid) {
             rangeValid = true;
             if(getData() != null) updateAxisRange();
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Wed May 23 16:09:59 2012 -0700
@@ -1249,7 +1249,8 @@
                         cacheEntry,
                         cacheable,
                         originatingNode,
-                        Font.getDefault()
+                        Font.getDefault(),
+                        styleList
                       )
                     : null;
                 if (font == null) font = Font.getDefault();
@@ -1331,7 +1332,8 @@
             final CacheEntry cacheEntry,
             final BooleanProperty cacheable,
             final Node originatingNode,
-            final Font font) 
+            final Font font,
+            final List<Style> styleList) 
     {
         
         if (node == null) return Font.getDefault();
@@ -1401,6 +1403,10 @@
             if (fontStyle != null && 
                 style.getStyle().equals(fontStyle.getStyle()) == false) {
                 
+                if (styleList != null) {
+                    styleList.add(fontStyle.getStyle());
+                }
+                
                 final Stylesheet.Origin fsOrigin = fontStyle.getOrigin();
                 if (origin == null || origin.compareTo(fsOrigin) < 0) {
                     origin = fsOrigin;
@@ -1420,7 +1426,7 @@
                     inheritedFont =
                         getFontForUseInConvertingRelativeSize(node.getParent(),
                             styleable, style, cacheEntry, cacheable, 
-                            originatingNode, font);
+                            originatingNode, font, styleList);
                 }
                 
                 Object value = resolved.convert(inheritedFont);
@@ -1439,7 +1445,7 @@
         }
 
         return getFontForUseInConvertingRelativeSize(node.getParent(), 
-                styleable, style, cacheEntry, cacheable, originatingNode, font);
+                styleable, style, cacheEntry, cacheable, originatingNode, font, styleList);
     }
     
     private CascadingStyle lookupFontSubPropertyStyle(final Node node, 
@@ -1644,6 +1650,10 @@
         
         if (csShorthand != null) {
             
+            if (styleList != null) {
+                styleList.add(csShorthand.getStyle());
+            }
+            
             // pull out the pieces. 
             final CalculatedValue cv = 
                 calculateValue(csShorthand, node, styleable, states, inlineStyles, 
@@ -1672,7 +1682,11 @@
         CascadingStyle csFamily = null; 
         if ((csFamily = lookupFontSubPropertyStyle(node, "-fx-font-family",
                 isUserSet, cacheable, csShorthand, distance)) != null) {
-       
+
+            if (styleList != null) {
+                styleList.add(csFamily.getStyle());
+            }
+            
             final CalculatedValue cv = 
                 calculateValue(csFamily, node, styleable, states, inlineStyles, 
                     originatingNode, cacheEntry, styleList);
@@ -1691,6 +1705,10 @@
         if ((csSize = lookupFontSubPropertyStyle(node, "-fx-font-size",
                 isUserSet, cacheable, csShorthand, distance))!= null) {
        
+            if (styleList != null) {
+                styleList.add(csSize.getStyle());
+            }
+
             final CalculatedValue cv = 
                 calculateValue(csSize, node, styleable, states, inlineStyles, 
                     originatingNode, cacheEntry, styleList);
@@ -1707,7 +1725,11 @@
         CascadingStyle csWeight = null;
         if ((csWeight = lookupFontSubPropertyStyle(node, "-fx-font-weight",
                 isUserSet, cacheable, csShorthand, distance))!= null) {
-       
+
+            if (styleList != null) {
+                styleList.add(csWeight.getStyle());
+            }
+            
             final CalculatedValue cv = 
                 calculateValue(csWeight, node, styleable, states, inlineStyles, 
                     originatingNode, cacheEntry, styleList);
@@ -1725,10 +1747,14 @@
         if ((csStyle = lookupFontSubPropertyStyle(node, "-fx-font-style",
                 isUserSet, cacheable, csShorthand, distance))!= null) {
        
-                final CalculatedValue cv = 
-                    calculateValue(csStyle, node, styleable, states, inlineStyles, 
-                        originatingNode, cacheEntry, styleList);
-                if (cv.isCacheable == false) cacheable.set(false);
+            if (styleList != null) {
+                styleList.add(csStyle.getStyle());
+            }
+            
+            final CalculatedValue cv = 
+                calculateValue(csStyle, node, styleable, states, inlineStyles, 
+                    originatingNode, cacheEntry, styleList);
+            if (cv.isCacheable == false) cacheable.set(false);
             if (cv.value instanceof FontPosture) {
                 style = (FontPosture)cv.value;
                 if (origin == null || origin.compareTo(cv.origin) < 0) {                        
--- a/javafx-ui-common/src/com/sun/javafx/css/parser/CSSLexer.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/parser/CSSLexer.java	Wed May 23 16:09:59 2012 -0700
@@ -364,6 +364,9 @@
 
     public void setReader(Reader reader) {
         this.reader = reader;
+        lastc = -1;
+        pos = offset = 0;
+        line = 1;
         this.currentState = initState;
         this.token = null;
         try {
@@ -374,25 +377,34 @@
     }
 
     private Token scanImportant()  throws IOException{
+        // CSS 2.1 grammar for important_sym
+        // "!"({w}|{comment})*{I}{M}{P}{O}{R}{T}{A}{N}{T}
         final Recognizer[] important_sym =
                 new Recognizer[] { I, M, P, O, R, T, A, N, T };
         int current = 0;
-
+        
+        text.append((char)ch);
+        
         // get past the '!'
         ch = readChar();
-
+       
         while(true) {
+            
             switch (ch) {
 
                 case Token.EOF:
                     token = Token.EOF_TOKEN;
                     return token;
 
-                case '/':
+                case '/':                    
                     ch = readChar();
                     if (ch == '*') skipComment();
-                    else return new Token(Token.INVALID);
-                    if (ch != -1) ch = readChar();
+                    else {
+                        text.append('/').append((char)ch);
+                        int temp = offset;
+                        offset = pos;
+                        return new Token(Token.INVALID, text.toString(), line, temp);
+                    }
                     break;
 
                 case ' ':
@@ -407,10 +419,13 @@
                     boolean accepted = true;
                     while(accepted && current < important_sym.length) {
                         accepted = important_sym[current++].recognize(ch);
+                        text.append((char)ch);
                         ch = readChar();
                     }
                     if (accepted) {
-                        return new Token(IMPORTANT_SYM, "!important");
+                        final int temp = offset;
+                        offset = pos-1; // will have read one char too many
+                        return new Token(IMPORTANT_SYM, "!important", line, temp);
                     } else {
                         while (ch != ';' &&
                                ch != '}' &&
@@ -418,7 +433,9 @@
                             ch = readChar();
                         }
                         if (ch != Token.EOF) {
-                            return Token.SKIP_TOKEN;
+                            final int temp = offset;
+                            offset = pos-1; // will have read one char too many
+                            return new Token(Token.SKIP, text.toString(), line, temp);
                         } else {
                             return Token.EOF_TOKEN;
                         }
@@ -532,6 +549,8 @@
             if (ch == '*') {
                 ch = readChar();
                 if (ch == '/') {
+                    offset = pos;
+                    ch=readChar();
                     break;
                 }
             } else {
@@ -540,7 +559,8 @@
         }
     }
 
-    private int pos = 1;
+    private int pos = 0;
+    private int offset = 0;
     private int line = 1;
     private int lastc = -1;
 
@@ -548,12 +568,17 @@
 
         int c = reader.read();
 
-        if (c == '\r' || (c == '\n' && lastc != '\r')) {
-            pos = 1;
+        // only reset line and pos counters after having read a NL since
+        // a NL token is created after the readChar
+        if (lastc == '\n' || (lastc == '\r' && c != '\n')) {
+            // set pos to 1 since we've already read the first char of the new line
+            pos = 1; 
+            offset = 0;
             line++;
         } else {
             pos++;
         }
+        
         lastc = c;
         return c;
     }
@@ -614,7 +639,7 @@
                     final int type = currentState.getType();
 
                     //
-                    // If the token is an INVALID and
+                    // If the token is INVALID and
                     // the currentState is something other than initState, then
                     // there is an error, so return INVALID.
                      //
@@ -622,9 +647,10 @@
                         !currentState.equals(initState)) {
 
                         final String str = text.toString();
-                        Token tok = new Token(type, str);
-                        tok.setOffset(pos);
-                        tok.setLine(line);
+                        Token tok = new Token(type, str, line, offset);
+                        // because the next char has already been read, 
+                        // the next token starts at pos-1
+                        offset = pos-1;
 
                         // return here, but the next char has already been read.
                         return tok;
@@ -650,9 +676,11 @@
                         }
 
                         if (ch != -1) {
-                            token = new Token(STRING, text.toString());
+                            token = new Token(STRING, text.toString(), line, offset);
+                            offset = pos;
                         } else {
-                            token = new Token(Token.INVALID);
+                            token = new Token(Token.INVALID, text.toString(), line, offset);
+                            offset = pos;
                         }
                         break;
 
@@ -661,8 +689,6 @@
                         if (ch == '*') {
                             skipComment();
                              if (ch != -1) {
-                                text.append((char)ch);
-                                ch = readChar();
                                 continue;
                             } else {
                                 token = Token.EOF_TOKEN;
@@ -670,79 +696,95 @@
                             }
                         } else {
                             // not a comment - a SOLIDUS
-                            token = new Token(SOLIDUS,"/");
+                            token = new Token(SOLIDUS,"/", line, offset);
+                            offset = pos;
                         }
                         break;
 
                     case '>':
 
-                        token = new Token(GREATER,">");
+                        token = new Token(GREATER,">", line, offset);
+                        offset = pos;
                         break;
 
                     case '{':
-                        token = new Token(LBRACE,"{");
+                        token = new Token(LBRACE,"{", line, offset);
+                        offset = pos;
                         break;
 
                     case '}':
-                        token = new Token(RBRACE,"}");
+                        token = new Token(RBRACE,"}", line, offset);
+                        offset = pos;
                         break;
 
                     case ';':
-                        token = new Token(SEMI,";");
+                        token = new Token(SEMI,";", line, offset);
+                        offset = pos;
                         break;
 
                     case ':':
-                        token = new Token(COLON,":");
+                        token = new Token(COLON,":", line, offset);
+                        offset = pos;
                         break;
 
                     case '*':
-                        token = new Token(STAR,"*");
+                        token = new Token(STAR,"*", line, offset);
+                        offset = pos;
                         break;
 
                     case '(':
-                        token = new Token(LPAREN,"(");
+                        token = new Token(LPAREN,"(", line, offset);
+                        offset = pos;
                         break;
 
                     case ')':
-                        token = new Token(RPAREN,")");
+                        token = new Token(RPAREN,")", line, offset);
+                        offset = pos;
                         break;
 
                     case ',':
-                        token = new Token(COMMA,",");
+                        token = new Token(COMMA,",", line, offset);
+                        offset = pos;
                         break;
 
                     case '.':
-                        token = new Token(DOT,".");
+                        token = new Token(DOT,".", line, offset);
+                        offset = pos;
                         break;
 
                     case ' ':
                     case '\t':
                     case '\f':
-                        token = new Token(WS, Character.toString((char)ch));
+                        token = new Token(WS, Character.toString((char)ch), line, offset);
+                        offset = pos;
                         break;
 
 
                     case '\r':
-                        token = new Token(NL);
-
+                        token = new Token(NL, "\\r", line, offset);
+                        // offset and pos are reset on next readChar
+                        
                         ch = readChar();
-                        if (ch != '\n') {
-                            token.setOffset(pos);
-                            token.setLine(line);
+                        if (ch == '\n') {
+                            token = new Token(NL, "\\r\\n", line, offset);
+                            // offset and pos are reset on next readChar
+                        } else {
+                            // already read the next character, so return
+                            // return the NL token here (avoid the readChar
+                            // at the end of the loop below)
                             final Token tok = token;
                             token = (ch == -1) ? Token.EOF_TOKEN : null;
                             return tok;
-                        }
+                        }                        
                         break;
 
                     case '\n':
-                        token = new Token(NL);
+                        token = new Token(NL, "\\n", line, offset);
+                        // offset and pos are reset on next readChar
                         break;
 
                     case '!':
                         Token tok = scanImportant();
-                        tok.setLine(line);
-                        tok.setOffset(pos);
                         return tok;
 
                     case '@':
@@ -754,25 +796,24 @@
                         if (ch == ';') {
                             ch = readChar();
                             token = Token.SKIP_TOKEN;
-
+                            offset = pos;
                         }
                         break;
 
                     default:
 //                      System.err.println("hit default case: ch = " + Character.toString((char)ch));
-                        token = new Token(Token.INVALID, Character.toString((char)ch));
+                        token = new Token(Token.INVALID, Character.toString((char)ch), line, offset);
+                        offset = pos;
                         break;
                 }
 
                 if (token == null) {
 //                    System.err.println("token is null! ch = " + Character.toString((char)ch));
-                    token = new Token(Token.INVALID, null);
+                    token = new Token(Token.INVALID, null, line, offset);
+                    offset = pos;
                 } else if (token.getType() == Token.EOF) {
                     return token;
-                } else {
-                    token.setLine(line);
-                    token.setOffset(pos);
-                }
+                } 
 
                 if (ch != -1) ch = readChar();
 
--- a/javafx-ui-common/src/com/sun/javafx/css/parser/Token.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/parser/Token.java	Wed May 23 16:09:59 2012 -0700
@@ -36,11 +36,15 @@
     final static Token INVALID_TOKEN = new Token(INVALID, "INVALID");
     final static Token SKIP_TOKEN = new Token(SKIP, "SKIP");
 
-    Token(int type, String text) {
+    Token(int type, String text, int line, int offset) {
         this.type = type;
         this.text = text;
-        this.line = -1;
-        this.offset = -1;
+        this.line = line;
+        this.offset = offset;        
+    }
+    
+    Token(int type, String text) {
+        this(type, text, -1, -1);
     }
 
     Token(int type) {
--- a/javafx-ui-common/src/javafx/scene/Scene.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Scene.java	Wed May 23 16:09:59 2012 -0700
@@ -110,6 +110,7 @@
 import javafx.beans.property.ReadOnlyDoubleWrapper;
 import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.beans.property.ReadOnlyObjectWrapper;
+import javafx.geometry.Orientation;
 import javafx.scene.image.WritableImage;
 import javafx.scene.input.GestureEvent;
 import javafx.scene.input.MouseDragEvent;
@@ -1430,6 +1431,23 @@
                     root.maxHeight(widthSetByUser >= 0 ? widthSetByUser : -1));
             computeHeight = true;
         }
+        if (root.getContentBias() == Orientation.HORIZONTAL) {
+            if (heightSetByUser < 0) {            
+                rootHeight = root.boundedSize(
+                        root.prefHeight(rootWidth),
+                        root.minHeight(rootWidth),
+                        root.maxHeight(rootWidth));
+                computeHeight = true;
+            }            
+        } else if (root.getContentBias() == Orientation.VERTICAL) {
+            if (widthSetByUser < 0) {
+                rootWidth = root.boundedSize(
+                        root.prefWidth(rootHeight),
+                        root.minWidth(rootHeight),
+                        root.maxWidth(rootHeight));
+                computeWidth = true;
+            }            
+        }        
         root.resize(rootWidth, rootHeight);
         doLayoutPass();
 
--- a/javafx-ui-common/src/javafx/scene/doc-files/cssref.html	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/doc-files/cssref.html	Wed May 23 16:09:59 2012 -0700
@@ -609,9 +609,8 @@
     <p>If the error is found while parsing a file, the file URL will be given.
       If the error is from an inline style (as in the example above), the URL is
       given as a question mark. The line and position give an offset into the
-      file or string where the token begins. <em>Note well!</em> The lexer does
-      a poor job of counting lines and characters. The line and position may not
-      be accurate. This should be resolved in a future release. <br>
+      file or string where the token begins. <em>Please note that the line and
+      position may not be accurate in releases prior to JavaFX 2.2.</em><br>
     </p>
     <p>Applications needing to detect errors from the parser can add a listener
       to the errors property of com.sun.javafx.css.StyleManager. This is not
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/Node_cssStyleMap_Test.java	Wed May 23 16:09:59 2012 -0700
@@ -26,6 +26,7 @@
 package com.sun.javafx.css;
 
 import com.sun.javafx.css.StyleHelper.StyleCacheKey;
+import com.sun.javafx.css.converters.FontConverter;
 import com.sun.javafx.css.converters.SizeConverter;
 import com.sun.javafx.tk.Toolkit;
 import javafx.scene.paint.Color;
@@ -37,6 +38,7 @@
 import java.util.List;
 import java.util.Map;
 import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.ObjectProperty;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.beans.value.WritableValue;
@@ -45,6 +47,8 @@
 import javafx.scene.Group;
 import javafx.scene.Scene;
 import javafx.scene.shape.Rectangle;
+import javafx.scene.text.Font;
+import javafx.scene.text.Text;
 import javafx.stage.Stage;
 import org.junit.Test;
 import static org.junit.Assert.*;
@@ -163,4 +167,140 @@
         assert(rect.impl_getStyleMap().isEmpty());
         
     }
+    
+    @Test
+    public void testRT_21212() {
+
+        final List<Declaration> rootDecls = new ArrayList<Declaration>();
+        Collections.addAll(rootDecls, 
+            new Declaration("-fx-font-size", new ParsedValue<ParsedValue<?,Size>,Double>(
+                new ParsedValue<Size,Size>(new Size(18, SizeUnits.PX), null), 
+                SizeConverter.getInstance()), false)
+        );
+        
+        final List<Selector> rootSels = new ArrayList<Selector>();
+        Collections.addAll(rootSels, 
+            Selector.createSelector("root")
+        );
+        
+        Rule rootRule = new Rule(rootSels, rootDecls);        
+        
+        Stylesheet stylesheet = new Stylesheet();
+        stylesheet.setOrigin(Stylesheet.Origin.AUTHOR);
+        stylesheet.getRules().add(rootRule);
+        
+        final List<CascadingStyle> styles = new ArrayList<CascadingStyle>();
+        for (Declaration decl : rootDecls) {
+            styles.add(
+                new CascadingStyle(
+                    new Style(rootSels.get(0), decl), 
+                    Collections.EMPTY_LIST,
+                    0, 
+                    0
+                )
+            );
+        }
+        
+        final ParsedValue[] fontValues = new ParsedValue[] {
+            new ParsedValue<String,String>("system", null),
+            new ParsedValue<ParsedValue<?,Size>,Double>(
+                new ParsedValue<Size,Size>(new Size(1, SizeUnits.EM), null),
+                SizeConverter.getInstance()
+            ), 
+            null,
+            null
+        };
+        final List<Declaration> textDecls = new ArrayList<Declaration>();
+        Collections.addAll(textDecls, 
+            new Declaration("-fx-font", new ParsedValue<ParsedValue[], Font>(
+                fontValues, FontConverter.getInstance()), false)
+        );
+        
+        final List<Selector> textSels = new ArrayList<Selector>();
+        Collections.addAll(textSels, 
+            Selector.createSelector("text")
+        );
+        
+        Rule textRule = new Rule(textSels, textDecls);        
+        stylesheet.getRules().add(textRule);
+        
+        for (Declaration decl : textDecls) {
+            styles.add(
+                new CascadingStyle(
+                    new Style(textSels.get(0), decl), 
+                    Collections.EMPTY_LIST,
+                    0, 
+                    0
+                )
+            );
+        }
+
+        // add to this list on wasAdded, check bean on wasRemoved.
+        final List<WritableValue> beans = new ArrayList<WritableValue>();
+        
+        final Map<WritableValue,List<Style>> styleMap = 
+                FXCollections.observableMap(new HashMap<WritableValue, List<Style>>());
+        
+        final Text text = new Text("HelloWorld") {
+
+            // I'm bypassing StyleManager by creating StyleHelper directly. 
+            StyleHelper shelper = null;
+                                   
+            @Override
+            public StyleHelper.StyleCacheKey impl_getStyleCacheKey() {
+                return shelper.createStyleCacheKey(this);
+            }
+            
+            @Override public StyleHelper impl_getStyleHelper() {
+                if (shelper == null) shelper = impl_createStyleHelper();
+                return shelper;
+            }            
+            
+            @Override
+            public StyleHelper impl_createStyleHelper() {
+                // If no styleclass, then create an StyleHelper with no mappings.
+                // Otherwise, create a StyleHelper matching the "rect" style class.
+                if (getStyleClass().isEmpty()) {
+                    shelper = StyleHelper.create(Collections.EMPTY_LIST, 0, 0);
+                    shelper.styleCache = new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheEntry>();
+                } else  {
+                    shelper = StyleHelper.create(styles, 0, 0);
+                    shelper.styleCache = new HashMap<StyleHelper.StyleCacheKey, StyleHelper.StyleCacheEntry>();
+                }
+                return shelper;
+            }
+        };
+                
+        final List<Declaration> expecteds = new ArrayList<Declaration>();
+        expecteds.addAll(rootDecls);
+        expecteds.addAll(textDecls);
+        text.getStyleClass().add("text");
+        text.impl_setStyleMap(FXCollections.observableMap(styleMap));
+        text.impl_getStyleMap().addListener(new MapChangeListener<WritableValue, List<Style>>() {
+
+            // a little different than the other tests since we should end up 
+            // with font and font-size in the map and nothing else. After all 
+            // the changes have been handled, the expecteds list should be empty.
+            public void onChanged(MapChangeListener.Change<? extends WritableValue, ? extends List<Style>> change) {
+                if (change.wasAdded()) {
+                    List<Style> styles = change.getValueAdded();
+                    for (Style style : styles) {
+                        assertTrue(expecteds.contains(style.getDeclaration()));
+                        expecteds.remove(style.getDeclaration());
+                    }
+                }
+            }
+        });
+               
+        text.impl_processCSS(true);
+        assertEquals(18, text.getFont().getSize(),0);
+        assertTrue(expecteds.isEmpty());
+
+        text.getStyleClass().clear();
+        text.impl_processCSS(true);
+        // Nothing new should be added since there are no styles.
+        // nchanges is decremented on remove, so it should be zero
+        assert(text.impl_getStyleMap().isEmpty());
+        
+    }    
 }
--- a/javafx-ui-common/test/unit/com/sun/javafx/css/parser/CSSLexerTest.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/css/parser/CSSLexerTest.java	Wed May 23 16:09:59 2012 -0700
@@ -284,4 +284,372 @@
         );
     }
 
+    @Test 
+    public void testTokenOffset() {
+        
+        String str =  "a: b;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3),
+            new Token(CSSLexer.SEMI,  ";", 1, 4),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+                
+    }
+    
+    @Test 
+    public void testTokenLineAndOffsetWithCR() {
+        
+        String str =  "a: b;\rc: d;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3),
+            new Token(CSSLexer.SEMI,  ";", 1, 4),
+            new Token(CSSLexer.NL,  "\\r", 1, 5),
+            new Token(CSSLexer.IDENT, "c", 2, 0),
+            new Token(CSSLexer.COLON, ":", 2, 1),
+            new Token(CSSLexer.WS,    " ", 2, 2),
+            new Token(CSSLexer.IDENT, "d", 2, 3),
+            new Token(CSSLexer.SEMI,  ";", 2, 4),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+                
+    }
+
+    @Test 
+    public void testTokenLineAndOffsetWithLF() {
+        
+        String str =  "a: b;\nc: d;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3),
+            new Token(CSSLexer.SEMI,  ";", 1, 4),
+            new Token(CSSLexer.NL,  "\\n", 1, 5),
+            new Token(CSSLexer.IDENT, "c", 2, 0),
+            new Token(CSSLexer.COLON, ":", 2, 1),
+            new Token(CSSLexer.WS,    " ", 2, 2),
+            new Token(CSSLexer.IDENT, "d", 2, 3),
+            new Token(CSSLexer.SEMI,  ";", 2, 4),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+                
+    }
+
+    @Test 
+    public void testTokenLineAndOffsetWithCRLF() {
+        //             012345   01234
+        String str =  "a: b;\r\nc: d;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3),
+            new Token(CSSLexer.SEMI,  ";", 1, 4),
+            new Token(CSSLexer.NL,  "\\r\\n", 1, 5),
+            new Token(CSSLexer.IDENT, "c", 2, 0),
+            new Token(CSSLexer.COLON, ":", 2, 1),
+            new Token(CSSLexer.WS,    " ", 2, 2),
+            new Token(CSSLexer.IDENT, "d", 2, 3),
+            new Token(CSSLexer.SEMI,  ";", 2, 4),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+                
+    }
+    
+    @Test 
+    public void testTokenOffsetWithEmbeddedComment() {
+        //             0123456789012345
+        String str =  "a: /*comment*/b;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 14), 
+            new Token(CSSLexer.SEMI,  ";", 1, 15),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+
+    @Test 
+    public void testTokenLineAndOffsetWithLeadingComment() {
+        //             012345678901 01234
+        String str =  "/*comment*/\na: b;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.NL, "\\n", 1, 11),
+            new Token(CSSLexer.IDENT, "a", 2, 0),
+            new Token(CSSLexer.COLON, ":", 2, 1),
+            new Token(CSSLexer.WS,    " ", 2, 2),
+            new Token(CSSLexer.IDENT, "b", 2, 3), 
+            new Token(CSSLexer.SEMI,  ";", 2, 4),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+    
+    @Test 
+    public void testTokenOffsetWithFunction() {
+        //             01234567890
+        String str =  "a: b(arg);";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3), 
+            new Token(CSSLexer.LPAREN, "(", 1, 4), 
+            new Token(CSSLexer.IDENT, "arg", 1, 5), 
+            new Token(CSSLexer.RPAREN, ")", 1, 8), 
+            new Token(CSSLexer.SEMI,  ";", 1, 9),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+    
+    @Test 
+    public void testTokenOffsetWithHash() {
+        //             01234567890
+        String str =  "a: #012345;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.HASH, "#012345", 1, 3), 
+            new Token(CSSLexer.SEMI,  ";", 1, 10),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+ 
+    @Test 
+    public void testTokenOffsetWithDigits() {
+        //             01234567890
+        String str =  "a: 123.45;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.NUMBER, "123.45", 1, 3), 
+            new Token(CSSLexer.SEMI,  ";", 1, 9),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+
+    @Test 
+    public void testTokenOffsetWithBangImportant() {
+        //             0123456789012345
+        String str =  "a: b !important;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3),
+            new Token(CSSLexer.WS,    " ", 1, 4),
+            new Token(CSSLexer.IMPORTANT_SYM, "!important", 1, 5), 
+            new Token(CSSLexer.SEMI,  ";", 1, 15),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+
+    @Test 
+    public void testTokenOffsetWithSkip() {
+        //             0123456789012345
+        String str =  "a: b !imporzant;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(CSSLexer.IDENT, "b", 1, 3),
+            new Token(CSSLexer.WS,    " ", 1, 4),
+            new Token(Token.SKIP, "!imporz", 1, 5), 
+            new Token(CSSLexer.SEMI,  ";", 1, 15),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+    
+    @Test 
+    public void testTokenOffsetWithInvalid() {
+        //             0123456789012345
+        String str =  "a: 1pz;";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.IDENT, "a", 1, 0),
+            new Token(CSSLexer.COLON, ":", 1, 1),
+            new Token(CSSLexer.WS,    " ", 1, 2),
+            new Token(Token.INVALID, "1pz", 1, 3),
+            new Token(CSSLexer.SEMI,  ";", 1, 6),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }
+
+    @Test
+    public void testTokenLineAndOffsetMoreFully() {
+        //             1            2                 3         4
+        //             012345678901 0123456789012345  012345678 0
+        String str =  "/*comment*/\n*.foo#bar:baz {\n\ta: 1em;\n}";
+        // [?][0] = line
+        // [?][1] = offset
+        Token[] expected = {
+            new Token(CSSLexer.NL,     "\\n",  1, 11),
+            new Token(CSSLexer.STAR,   "*",    2, 0),
+            new Token(CSSLexer.DOT,    ".",    2, 1),
+            new Token(CSSLexer.IDENT,  "foo",  2, 2),
+            new Token(CSSLexer.HASH,   "#bar", 2, 5),
+            new Token(CSSLexer.COLON,  ":",    2, 9),
+            new Token(CSSLexer.IDENT,  "baz",  2, 10),
+            new Token(CSSLexer.WS,     " ",    2, 13),
+            new Token(CSSLexer.LBRACE, "{",    2, 14),
+            new Token(CSSLexer.NL,     "\\n",  2, 15),
+            new Token(CSSLexer.WS,     "\t",   3, 0),
+            new Token(CSSLexer.IDENT,  "a",    3, 1),
+            new Token(CSSLexer.COLON,  ":",    3, 2),
+            new Token(CSSLexer.WS,     " ",    3, 3),
+            new Token(CSSLexer.EMS,    "1em",  3, 4), 
+            new Token(CSSLexer.SEMI,   ";",    3, 7),
+            new Token(CSSLexer.NL,     "\\n",  3, 8),
+            new Token(CSSLexer.RBRACE, "}",    4, 0),
+            Token.EOF_TOKEN
+        };
+        
+        List<Token> tlist = getTokens(str);
+        checkTokens(tlist, expected);
+        
+        for(int n=0; n<tlist.size(); n++) {
+            Token tok = tlist.get(n);
+            assertEquals("bad line. tok="+tok, expected[n].getLine(), tok.getLine());
+            assertEquals("bad offset. tok="+tok, expected[n].getOffset(), tok.getOffset());
+        }
+    }    
 }
--- a/javafx-ui-common/test/unit/javafx/scene/SceneTest.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-common/test/unit/javafx/scene/SceneTest.java	Wed May 23 16:09:59 2012 -0700
@@ -34,6 +34,9 @@
 import javafx.stage.Stage;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.TilePane;
+import javafx.scene.layout.VBox;
 
 import org.junit.After;
 import org.junit.Before;
@@ -517,6 +520,24 @@
     }
 
     @Test
+    public void testSceneSizeWithContentBiasOnRoot() {
+        Rectangle r1 = new Rectangle(20, 20);
+        Rectangle r2 = new Rectangle(20, 20);
+        Rectangle r3 = new Rectangle(100, 20);
+        
+        TilePane tilePane = new TilePane();
+        tilePane.getChildren().addAll(r1, r2);
+
+        final VBox root = new VBox();
+        root.getChildren().addAll(tilePane, r3);
+        Scene scene = new Scene(root);
+        stage.setScene(scene);
+                
+        assertEquals(100, (int) scene.getWidth());
+        assertEquals(40, (int) scene.getHeight());
+    }
+    
+    @Test
     public void focusChangeShouldBeAtomic() {
         final Group root = new Group();
 
--- a/javafx-ui-controls/src/com/sun/javafx/charts/Legend.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/charts/Legend.java	Wed May 23 16:09:59 2012 -0700
@@ -138,7 +138,8 @@
             if(columns <= 1) return tileSize.getWidth() + getInsets().getLeft() + getInsets().getRight();
         } else {
             rows = (int) Math.floor( contentHeight / (tileSize.getHeight() + GAP) );
-            columns = (int)Math.ceil(getItems().size() / (double)rows);
+            columns = (rows == 0) ? (int)Math.ceil(getItems().size()) : 
+                            (int)Math.ceil(getItems().size() / (double)rows);
         }
         if(columns == 1) rows = Math.min(rows, getItems().size());
         return (columns*(tileSize.getWidth()+GAP)) - GAP + getInsets().getLeft() + getInsets().getRight();
@@ -151,7 +152,8 @@
             if(rows <= 1) return tileSize.getHeight() + getInsets().getTop() + getInsets().getBottom();
         } else {
             columns = (int) Math.floor( contentWidth / (tileSize.getWidth() + GAP) );
-            rows = (int)Math.ceil(getItems().size() / (double)columns);
+            rows = (columns == 0) ? (int)Math.ceil(getItems().size()) : 
+                            (int)Math.ceil(getItems().size() / (double)columns);
         }
         if(rows == 1) columns = Math.min(columns, getItems().size());
         return (rows*(tileSize.getHeight()+GAP)) - GAP + getInsets().getTop() + getInsets().getBottom();
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Wed May 23 16:09:59 2012 -0700
@@ -35,6 +35,7 @@
 import javafx.scene.control.ListView;
 import javafx.scene.control.MultipleSelectionModel;
 import javafx.scene.control.SelectionMode;
+import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 
 /**
@@ -160,7 +161,8 @@
             map.remove(listView);
         }
         
-        if (e.isPrimaryButtonDown() || (e.isSecondaryButtonDown() && !selected)) { 
+        MouseButton button = e.getButton();
+        if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) { 
             if (sm.getSelectionMode() == SelectionMode.SINGLE) {
                 simpleSelect(e);
             } else {
@@ -204,7 +206,7 @@
         lv.getSelectionModel().clearAndSelect(index);
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.isPrimaryButtonDown()) {
+        if (e.getButton() == MouseButton.PRIMARY) {
             if (e.getClickCount() == 1 && isAlreadySelected) {
                 lv.edit(index);
             } else if (e.getClickCount() == 1) {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableCellBehavior.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableCellBehavior.java	Wed May 23 16:09:59 2012 -0700
@@ -24,16 +24,25 @@
  */
 package com.sun.javafx.scene.control.behavior;
 
+import com.sun.javafx.PlatformUtil;
 import java.util.List;
 import java.util.WeakHashMap;
 
 import javafx.scene.control.*;
 import javafx.scene.control.TableView.TableViewFocusModel;
+import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 
 /**
  */
 public class TableCellBehavior extends CellBehaviorBase<TableCell> {
+    
+    /***************************************************************************
+     *                                                                         *
+     * Private static implementation                                           *
+     *                                                                         *
+     **************************************************************************/
+    
     // global map used to store the focus cell for a table view when it is first
     // shift-clicked. This allows for proper keyboard interactions, in particular
     // resolving RT-11446
@@ -58,26 +67,59 @@
         return map.containsKey(table) && map.get(table) != null;
     }
     
+    
+    
+    /***************************************************************************
+     *                                                                         *
+     * Private fields                                                          *
+     *                                                                         *
+     **************************************************************************/      
+    
     // For RT-17456: have selection occur as fast as possible with mouse input.
     // The idea is (consistently with some native applications we've tested) to 
     // do the action as soon as you can. It takes a bit more coding but provides
     // the best feel:
     //  - when you click on a not-selected item, you can select immediately on press
     //  - when you click on a selected item, you need to wait whether DragDetected or Release comes first 
-    private boolean selected = false;
+    // To support touch devices, we have to slightly modify this behavior, such
+    // that selection only happens on mouse release, if only minimal dragging
+    // has occurred.
     private boolean latePress = false;
+    private final boolean isEmbedded = PlatformUtil.isEmbedded();
+    private boolean wasSelected = false;
+    
+    
+
+    /***************************************************************************
+     *                                                                         *
+     * Constructors                                                            *
+     *                                                                         *
+     **************************************************************************/    
 
     public TableCellBehavior(TableCell control) {
         super(control);
     }
     
+    
+    /***************************************************************************
+     *                                                                         *
+     * Public API                                                              *
+     *                                                                         *
+     **************************************************************************/    
+    
     @Override public void mousePressed(MouseEvent event) {
-        if (selected) {
+        boolean selectedBefore = getControl().isSelected();
+        
+        if (getControl().isSelected()) {
             latePress = true;
             return;
         }
+
+        doSelect(event);
         
-        doSelect(event);
+        if (isEmbedded && selectedBefore) {
+            wasSelected = getControl().isSelected();
+        }
     }
     
     @Override public void mouseReleased(MouseEvent event) {
@@ -85,11 +127,28 @@
             latePress = false;
             doSelect(event);
         }
+        
+        wasSelected = false;
     }
     
     @Override public void mouseDragged(MouseEvent event) {
         latePress = false;
+        
+        // the mouse has now been dragged on a touch device, we should
+        // remove the selection if we just added it in the last mouse press
+        // event
+        if (isEmbedded && ! wasSelected && getControl().isSelected()) {
+            getControl().getTableView().getSelectionModel().clearSelection(getControl().getIndex());
+        }
     }
+    
+    
+    
+    /***************************************************************************
+     *                                                                         *
+     * Private implementation                                                  *
+     *                                                                         *
+     **************************************************************************/      
 
     private void doSelect(MouseEvent e) {
         // Note that table.select will reset selection
@@ -131,7 +190,8 @@
 
         // we must update the table appropriately, and this is determined by
         // what modifiers the user held down as they released the mouse.
-        if (e.isPrimaryButtonDown() || (e.isSecondaryButtonDown() && !selected)) { 
+        MouseButton button = e.getButton();
+        if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) { 
             if (sm.getSelectionMode() == SelectionMode.SINGLE) {
                 simpleSelect(e);
             } else {
@@ -187,7 +247,7 @@
         tv.getSelectionModel().clearAndSelect(row, getControl().getTableColumn());
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.isPrimaryButtonDown()) {
+        if (e.getButton() == MouseButton.PRIMARY) {
             if (e.getClickCount() == 1 && isAlreadySelected) {
                 tv.edit(row, getControl().getTableColumn());
             } else if (e.getClickCount() == 1) {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Wed May 23 16:09:59 2012 -0700
@@ -25,17 +25,26 @@
 
 package com.sun.javafx.scene.control.behavior;
 
+import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.logging.PlatformLogger;
 import com.sun.javafx.scene.control.Logging;
 import java.util.WeakHashMap;
 
 import javafx.scene.Node;
 import javafx.scene.control.*;
+import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
 
 /**
  */
 public class TreeCellBehavior extends CellBehaviorBase<TreeCell<?>> {
+    
+    /***************************************************************************
+     *                                                                         *
+     * Private static implementation                                           *
+     *                                                                         *
+     **************************************************************************/
+    
     // global map used to store the focus index for a tree view when it is first
     // shift-clicked. This allows for proper keyboard interactions, in particular
     // resolving RT-11446
@@ -60,26 +69,61 @@
         return map.containsKey(tree) && map.get(tree) != -1;
     }
     
+    
+    
+    /***************************************************************************
+     *                                                                         *
+     * Private fields                                                          *
+     *                                                                         *
+     **************************************************************************/    
+    
     // For RT-17456: have selection occur as fast as possible with mouse input.
     // The idea is (consistently with some native applications we've tested) to 
     // do the action as soon as you can. It takes a bit more coding but provides
     // the best feel:
     //  - when you click on a not-selected item, you can select immediately on press
     //  - when you click on a selected item, you need to wait whether DragDetected or Release comes first 
-    private boolean selected = false;
+    // To support touch devices, we have to slightly modify this behavior, such
+    // that selection only happens on mouse release, if only minimal dragging
+    // has occurred.
     private boolean latePress = false;
+    private final boolean isEmbedded = PlatformUtil.isEmbedded();
+    private boolean wasSelected = false;
+
+    
+    
+    
+    /***************************************************************************
+     *                                                                         *
+     * Constructors                                                            *
+     *                                                                         *
+     **************************************************************************/
     
     public TreeCellBehavior(final TreeCell control) {
         super(control);
     }
+    
+    
+    
+    /***************************************************************************
+     *                                                                         *
+     * Public API                                                              *
+     *                                                                         *
+     **************************************************************************/    
 
     @Override public void mousePressed(MouseEvent event) {
-        if (selected) {
+        boolean selectedBefore = getControl().isSelected();
+        
+        if (getControl().isSelected()) {
             latePress = true;
             return;
         }
+
+        doSelect(event);
         
-        doSelect(event);
+        if (isEmbedded && selectedBefore) {
+            wasSelected = getControl().isSelected();
+        }
     }
     
     @Override public void mouseReleased(MouseEvent event) {
@@ -87,12 +131,29 @@
             latePress = false;
             doSelect(event);
         }
+        
+        wasSelected = false;
     }
     
     @Override public void mouseDragged(MouseEvent event) {
         latePress = false;
+        
+        // the mouse has now been dragged on a touch device, we should
+        // remove the selection if we just added it in the last mouse press
+        // event
+        if (isEmbedded && ! wasSelected && getControl().isSelected()) {
+            getControl().getTreeView().getSelectionModel().clearSelection(getControl().getIndex());
+        }
     }
     
+    
+    
+    /***************************************************************************
+     *                                                                         *
+     * Private implementation                                                  *
+     *                                                                         *
+     **************************************************************************/      
+    
     private void doSelect(MouseEvent event) {
         // we update the cell to point to the new tree node
         TreeCell<?> treeCell = getControl();
@@ -142,8 +203,9 @@
         } else {
             map.remove(treeView);
         }
-
-        if (event.isPrimaryButtonDown() || (event.isSecondaryButtonDown() && !selected)) { 
+        
+        MouseButton button = event.getButton();
+        if (button == MouseButton.PRIMARY || (button == MouseButton.SECONDARY && !selected)) { 
             if (sm.getSelectionMode() == SelectionMode.SINGLE) {
                 simpleSelect(event);
             } else {
@@ -186,13 +248,13 @@
         tv.getSelectionModel().clearAndSelect(index);
 
         // handle editing, which only occurs with the primary mouse button
-        if (e.isPrimaryButtonDown()) {
+        if (e.getButton() == MouseButton.PRIMARY) {
             if (e.getClickCount() == 1 && isAlreadySelected) {
                 tv.edit(getControl().getTreeItem());
             } else if (e.getClickCount() == 1) {
                 // cancel editing
                 tv.edit(null);
-            } else if (e.getClickCount() == 2 && getControl().isEditable()) {
+            } else if (e.getClickCount() == 2 && ! getControl().isEditable()) {
                 // try to expand/collapse tree item
                 getControl().getTreeItem().setExpanded(! getControl().getTreeItem().isExpanded());
             }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ColorPalette.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ColorPalette.java	Wed May 23 16:09:59 2012 -0700
@@ -209,7 +209,19 @@
                                     (index-1) : (NUM_OF_ROWS*NUM_OF_COLUMNS)-1);
                 prevSquare.requestFocus();
                 focusedSquare = prevSquare;
-                break;
+                return;
+            } 
+        }
+        // check custom colors
+        int len = customColorGrid.getChildren().size();
+        for (index = len-1; index >= 0; index--) {
+            ColorSquare cs = (ColorSquare)customColorGrid.getChildren().get(index);
+            if (cs == focusedSquare) {
+                ColorSquare prevSquare = (ColorSquare)customColorGrid.getChildren().get((index != 0) ? 
+                                    (index-1) : len-1);
+                prevSquare.requestFocus();
+                focusedSquare = prevSquare;
+                return;
             } 
         }
         if (index == -1) {
@@ -228,9 +240,26 @@
                         (index-12) : ((NUM_OF_ROWS-1)*NUM_OF_COLUMNS)+index);
                 prevSquare.requestFocus();
                 focusedSquare = prevSquare;
-                break;
+                return;
             } 
         }
+        int len = customColorGrid.getChildren().size();
+        for (index = len-1; index >= 0; index--) {
+            // check custom colors
+            ColorSquare cs = (ColorSquare)customColorGrid.getChildren().get(index);
+            ColorSquare prevSquare = null;
+            if (cs == focusedSquare) {
+                if (index -12 >= 0) {
+                    prevSquare = (ColorSquare)customColorGrid.getChildren().get(index-12);
+                } else {
+                    int rowIndex = customColorGrid.getRowIndex(customColorGrid.getChildren().get(len-1));
+                    prevSquare = (ColorSquare)customColorGrid.getChildren().get((rowIndex*NUM_OF_COLUMNS)+index);
+                }
+                prevSquare.requestFocus();
+                focusedSquare = prevSquare;
+                return;
+            }
+        }
         if (index == -1) {
             ColorSquare cs = colorPickerGrid.getSquares().get((NUM_OF_ROWS*NUM_OF_COLUMNS)-1);
             focusedSquare = cs;
@@ -247,10 +276,22 @@
                         (index != (NUM_OF_ROWS*NUM_OF_COLUMNS)-1) ? (index+1) : 0);
                 prevSquare.requestFocus();
                 focusedSquare = prevSquare;
-                break;
+                return;
             } 
         }
-        if (index == (NUM_OF_ROWS*NUM_OF_COLUMNS)) {
+        // check custom colors
+        int len = customColorGrid.getChildren().size();
+        for (index = 0; index < len; index++) {
+            ColorSquare cs = (ColorSquare)customColorGrid.getChildren().get(index);
+            if (cs == focusedSquare) {
+                ColorSquare prevSquare = (ColorSquare)customColorGrid.getChildren().get(
+                        (index != len-1) ? (index+1) : 0);
+                prevSquare.requestFocus();
+                focusedSquare = prevSquare;
+                return;
+            } 
+        }
+        if (index == len) {
             ColorSquare cs = colorPickerGrid.getSquares().get(0);
             focusedSquare = cs;
             focusedSquare.requestFocus();
@@ -266,10 +307,27 @@
                         (index+12) : index-((NUM_OF_ROWS-1)*NUM_OF_COLUMNS));
                 prevSquare.requestFocus();
                 focusedSquare = prevSquare;
-                break;
+                return;
             } 
         }
-        if (index == (NUM_OF_ROWS*NUM_OF_COLUMNS)) {
+        // check custom colors
+        int len = customColorGrid.getChildren().size();
+        for (index = 0; index < len; index++) {
+            ColorSquare cs = (ColorSquare)customColorGrid.getChildren().get(index);
+            ColorSquare prevSquare = null;
+            if (cs == focusedSquare) {
+                if (index+12 < len) {
+                    prevSquare = (ColorSquare)customColorGrid.getChildren().get(index+12);
+                } else {
+                    int rowIndex = customColorGrid.getRowIndex(customColorGrid.getChildren().get(len-1));
+                    prevSquare = (ColorSquare)customColorGrid.getChildren().get(index-(rowIndex)*NUM_OF_COLUMNS);
+                }
+                prevSquare.requestFocus();
+                focusedSquare = prevSquare;
+                return;
+            } 
+        }
+        if (index == len) {
             ColorSquare cs = colorPickerGrid.getSquares().get(0);
             focusedSquare.requestFocus();
             focusedSquare = cs;
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ComboBoxBaseSkin.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ComboBoxBaseSkin.java	Wed May 23 16:09:59 2012 -0700
@@ -122,12 +122,8 @@
     }
     
     private void updateDisplayArea() {
-        if (displayNode != null) {
-            getChildren().remove(displayNode);
-            displayNode = null;
-        }
         displayNode = getDisplayNode();
-        getChildren().add(0, displayNode);
+        getChildren().setAll(displayNode, arrowButton);
     }
     
     private boolean isButton() {
@@ -159,7 +155,7 @@
         
         if (isButton()) return;
         
-        arrowButton.resize(arrowButtonWidth, getHeight());
+        arrowButton.resize(arrowButtonWidth, getHeight() - padding.getTop() - padding.getBottom());
         positionInArea(arrowButton, getWidth() - padding.getRight() - arrowButtonWidth, 0, 
                 arrowButtonWidth, getHeight(), 0, HPos.CENTER, VPos.CENTER);
     }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/LabeledImpl.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/LabeledImpl.java	Wed May 23 16:09:59 2012 -0700
@@ -36,13 +36,19 @@
 
 import com.sun.javafx.css.StyleableProperty;
 import com.sun.javafx.css.Stylesheet;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import javafx.beans.property.Property;
 import javafx.beans.value.WritableValue;
+import javafx.scene.Parent;
 
 
 public class LabeledImpl extends Label {
 
+    public LabeledImpl(final Labeled labeled) {
+        this.shuttler = new Shuttler(this, labeled);
+    }
+        
     final private Shuttler shuttler;
     
     private static void initialize(Shuttler shuttler, LabeledImpl labeledImpl, Labeled labeled) {
@@ -53,7 +59,7 @@
         labeledImpl.setGraphic(labeled.getGraphic());
         labeled.graphicProperty().addListener(shuttler);
         
-        final List<StyleableProperty> styleables = Labeled.impl_CSS_STYLEABLES();
+        final List<StyleableProperty> styleables = StyleableProperties.STYLEABLES_TO_MIRROR;
         
         for(int n=0, nMax=styleables.size(); n<nMax; n++) {
             final StyleableProperty styleable = styleables.get(n);
@@ -111,7 +117,32 @@
         }
     }
 
-    public LabeledImpl(final Labeled labeled) {
-        this.shuttler = new Shuttler(this, labeled);
+    /** Protected for unit test purposes */
+    static final class StyleableProperties {
+
+        static final List<StyleableProperty> STYLEABLES_TO_MIRROR;
+        static {
+            //
+            // We do this as we only want to mirror the Labeled's keys,
+            // none of Parent's, otherwise all of the properties on Parent,
+            // like opacity, would be applied twice (once to the Labeled and 
+            // again to the LabeledImpl). 
+            //
+            // Note, however, that this subset is not the list of properties
+            // for this LabeledImpl that can be styled. For that, we want all
+            // the properites that are inherited by virtue of LabeledImpl 
+            // being a Label. This allows for the LabledImpl to be styled
+            // with styles like .menu-button .label { -fx-opacity: 80%; }
+            // If just this subset were returned (by impl_CSS_STYLEABLE) then
+            // -fx-opacity (for example) would be meaningless to the Labeled. 
+            // 
+            final List<StyleableProperty> labeledStyleables = Labeled.impl_CSS_STYLEABLES();
+            final List<StyleableProperty> parentStyleables = Parent.impl_CSS_STYLEABLES();
+            final List<StyleableProperty> styleables = 
+                new ArrayList<StyleableProperty>(labeledStyleables);
+            styleables.removeAll(parentStyleables);
+            STYLEABLES_TO_MIRROR = Collections.unmodifiableList(styleables);
+        }
     }
+
 }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/PaginationSkin.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/PaginationSkin.java	Wed May 23 16:09:59 2012 -0700
@@ -44,6 +44,7 @@
 
 package com.sun.javafx.scene.control.skin;
 
+import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.css.StyleableBooleanProperty;
 import com.sun.javafx.css.StyleableObjectProperty;
 import com.sun.javafx.css.StyleableProperty;
@@ -87,6 +88,7 @@
     private static final double THRESHOLD = 0.30;
 
     private Pagination pagination;
+    private StackPane stackPane;
     private ScrollPane currentScrollPane;
     private ScrollPane nextScrollPane;
     private Timeline timeline;
@@ -110,6 +112,9 @@
         setClip(clipRect);
 
         this.pagination = pagination;
+
+        this.stackPane = new StackPane();
+
         this.currentScrollPane = new ScrollPane();
         currentScrollPane.getStyleClass().add("page");
         currentScrollPane.setFitToWidth(true);
@@ -127,7 +132,8 @@
 
         this.navigation = new NavigationControl();
 
-        getChildren().addAll(currentScrollPane, nextScrollPane, navigation);
+        stackPane.getChildren().addAll(currentScrollPane, nextScrollPane);
+        getChildren().addAll(stackPane, navigation);
 
         pagination.maxPageIndicatorCountProperty().addListener(new InvalidationListener() {
             @Override
@@ -159,103 +165,105 @@
     private double pressPos;
     private boolean touchMoved = false;
     private void initializeSwipeAndTouchHandlers() {
-        setOnSwipeLeft(new EventHandler<SwipeEvent>() {
-            @Override public void handle(SwipeEvent t) {
-                touchMoved = false;
-                selectNext();
-                t.consume();
-            }
-        });
+        if (PlatformUtil.isEmbedded()) {
+            stackPane.setOnSwipeLeft(new EventHandler<SwipeEvent>() {
+                @Override public void handle(SwipeEvent t) {
+                    touchMoved = false;
+                    selectNext();
+                    t.consume();
+                }
+            });
 
-        setOnSwipeRight(new EventHandler<SwipeEvent>() {
-            @Override public void handle(SwipeEvent t) {
-                touchMoved = false;
-                selectPrevious();
-                t.consume();
-            }
-        });
+            stackPane.setOnSwipeRight(new EventHandler<SwipeEvent>() {
+                @Override public void handle(SwipeEvent t) {
+                    touchMoved = false;
+                    selectPrevious();
+                    t.consume();
+                }
+            });
 
-        setOnScrollStarted(new EventHandler<ScrollEvent>() {
-            @Override public void handle(ScrollEvent e) {
-                pressPos = e.getSceneX();
-                touchMoved = true;
-                e.consume();
-            }
-        });
+            stackPane.setOnScrollStarted(new EventHandler<ScrollEvent>() {
+                @Override public void handle(ScrollEvent e) {
+                    pressPos = e.getSceneX();
+                    touchMoved = true;
+                    e.consume();
+                }
+            });
 
-        setOnScroll(new EventHandler<ScrollEvent>() {
-            @Override public void handle(ScrollEvent e) {
-                if (!touchMoved) {
-                    // Ignore any scroll events after the scrolling has finished.
-                    return;
-                }
-                
-                touchMoved = true;
-                double delta = e.getSceneX() - pressPos;
-                double width = getWidth() - (getInsets().getLeft() + getInsets().getRight());
-                double currentScrollPaneX;
-                double nextScrollPaneX;
+            stackPane.setOnScroll(new EventHandler<ScrollEvent>() {
+                @Override public void handle(ScrollEvent e) {
+                    if (!touchMoved) {
+                        // Ignore any scroll events after the scrolling has finished.
+                        return;
+                    }
 
-                if (delta < 0) {
-                    // right to left
-                    if (Math.abs(delta) <= width) {
-                        currentScrollPaneX = delta;
-                        nextScrollPaneX = width + delta;
-                    } else {
-                        currentScrollPaneX = -width;
-                        nextScrollPaneX = 0;
-                    }
-                    currentScrollPane.setTranslateX(currentScrollPaneX);
-                    if (pagination.getCurrentPageIndex() < getPageCount() - 1) {
-                        createPage(nextScrollPane, currentIndex + 1);
-                        nextScrollPane.setVisible(true);
-                        nextScrollPane.setTranslateX(nextScrollPaneX);
-                    } else {
-                        currentScrollPane.setTranslateX(0);
-                    }
-                } else {
-                    // left to right
-                    if (Math.abs(delta) <= width) {
-                        currentScrollPaneX = delta;
-                        nextScrollPaneX = -width + delta;
-                    } else {
-                        currentScrollPaneX = width;
-                        nextScrollPaneX = 0;
-                    }
-                    currentScrollPane.setTranslateX(currentScrollPaneX);
-                    if (pagination.getCurrentPageIndex() != 0) {
-                        createPage(nextScrollPane, currentIndex - 1);
-                        nextScrollPane.setVisible(true);
-                        nextScrollPane.setTranslateX(nextScrollPaneX);
-                    } else {
-                        currentScrollPane.setTranslateX(0);
-                    }
-                }
-                e.consume();
-            }
-        });
+                    touchMoved = true;
+                    double delta = e.getSceneX() - pressPos;
+                    double width = getWidth() - (getInsets().getLeft() + getInsets().getRight());
+                    double currentScrollPaneX;
+                    double nextScrollPaneX;
 
-        setOnScrollFinished(new EventHandler<ScrollEvent>() {
-            @Override
-            public void handle(ScrollEvent e) {
-                double delta = Math.abs(e.getSceneX() - pressPos);
-                double width = getWidth() - (getInsets().getLeft() + getInsets().getRight());
-                double threshold = delta/width;
-                if (touchMoved) {
-                    if (threshold > THRESHOLD) {
-                        if (pressPos > e.getSceneX()) {
-                            selectNext();
+                    if (delta < 0) {
+                        // right to left
+                        if (Math.abs(delta) <= width) {
+                            currentScrollPaneX = delta;
+                            nextScrollPaneX = width + delta;
                         } else {
-                            selectPrevious();
+                            currentScrollPaneX = -width;
+                            nextScrollPaneX = 0;
+                        }
+                        currentScrollPane.setTranslateX(currentScrollPaneX);
+                        if (pagination.getCurrentPageIndex() < getPageCount() - 1) {
+                            createPage(nextScrollPane, currentIndex + 1);
+                            nextScrollPane.setVisible(true);
+                            nextScrollPane.setTranslateX(nextScrollPaneX);
+                        } else {
+                            currentScrollPane.setTranslateX(0);
                         }
                     } else {
-                        animateClamping(pressPos > e.getSceneX());
+                        // left to right
+                        if (Math.abs(delta) <= width) {
+                            currentScrollPaneX = delta;
+                            nextScrollPaneX = -width + delta;
+                        } else {
+                            currentScrollPaneX = width;
+                            nextScrollPaneX = 0;
+                        }
+                        currentScrollPane.setTranslateX(currentScrollPaneX);
+                        if (pagination.getCurrentPageIndex() != 0) {
+                            createPage(nextScrollPane, currentIndex - 1);
+                            nextScrollPane.setVisible(true);
+                            nextScrollPane.setTranslateX(nextScrollPaneX);
+                        } else {
+                            currentScrollPane.setTranslateX(0);
+                        }
                     }
+                    e.consume();
                 }
-                touchMoved = false;
-                e.consume();
-            }
-        });
+            });
+
+            stackPane.setOnScrollFinished(new EventHandler<ScrollEvent>() {
+                @Override
+                public void handle(ScrollEvent e) {
+                    double delta = Math.abs(e.getSceneX() - pressPos);
+                    double width = getWidth() - (getInsets().getLeft() + getInsets().getRight());
+                    double threshold = delta/width;
+                    if (touchMoved) {
+                        if (threshold > THRESHOLD) {
+                            if (pressPos > e.getSceneX()) {
+                                selectNext();
+                            } else {
+                                selectPrevious();
+                            }
+                        } else {
+                            animateClamping(pressPos > e.getSceneX());
+                        }
+                    }
+                    touchMoved = false;
+                    e.consume();
+                }
+            });
+        }
     }
 
     private void resetIndexes(boolean usePageIndex) {
@@ -644,8 +652,7 @@
         double navigationHeight = snapSize(navigation.prefHeight(-1));
         double scrollPaneHeight = snapSize(height - navigationHeight);
 
-        layoutInArea(currentScrollPane, left, top, width, scrollPaneHeight, 0, HPos.CENTER, VPos.CENTER);
-        layoutInArea(nextScrollPane, left, top, width, scrollPaneHeight, 0, HPos.CENTER, VPos.CENTER);
+        layoutInArea(stackPane, left, top, width, scrollPaneHeight, 0, HPos.CENTER, VPos.CENTER);
         layoutInArea(navigation, left, scrollPaneHeight, width, navigationHeight, 0, HPos.CENTER, VPos.CENTER);
     }
 
@@ -835,8 +842,20 @@
                     maxPageIndicatorCount = toIndex - fromIndex;
                 }
 
-                pageCount = maxPageIndicatorCount;
-                int lastIndicatorButtonIndex = maxPageIndicatorCount - 1;
+                int lastIndicatorButtonIndex;
+                if (pageCount > maxPageIndicatorCount) {
+                    pageCount = maxPageIndicatorCount;
+                    lastIndicatorButtonIndex = maxPageIndicatorCount - 1;
+                 } else {
+                    if (indicatorCount > getPageCount()) {
+                        pageCount = getPageCount();
+                        lastIndicatorButtonIndex = getPageCount() - 1;
+                    } else {
+                        pageCount = indicatorCount;
+                        lastIndicatorButtonIndex = indicatorCount - 1;
+                    }
+                }
+
                 if (currentIndex >= toIndex) {
                     // The current index has fallen off the right
                     toIndex = currentIndex;
@@ -851,7 +870,7 @@
 
                 if (toIndex > getPageCount() - 1) {
                     toIndex = getPageCount() - 1;
-                    fromIndex = toIndex - lastIndicatorButtonIndex;
+                    //fromIndex = toIndex - lastIndicatorButtonIndex;
                 }
 
                 if (fromIndex < 0) {
@@ -895,7 +914,7 @@
                     return false;
                 } else {
                   toIndex = getPageCount() - 1;
-                  fromIndex = toIndex - lastIndicatorButtonIndex;
+                  //fromIndex = toIndex - lastIndicatorButtonIndex;
                 }
             }
 
@@ -946,8 +965,8 @@
                     i += maxPageIndicatorCount;
                 }
             }
-            // We should never be here
-            return -1;
+            // We are on the last page set going back to the previous page set
+            return maxPageIndicatorCount - 1;
         }
 
         private Pos sideToPos(Side s) {
@@ -1029,6 +1048,9 @@
                 // Grey out the right arrow if we have reached the end.
                 rightArrowButton.setDisable(true);
             }
+            // Reapply CSS so the left and right arrow button's disable state is updated
+            // immediately.
+            impl_reapplyCSS();
 
             leftArrowButton.setVisible(isArrowsVisible());
             rightArrowButton.setVisible(isArrowsVisible());
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableColumnHeader.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TableColumnHeader.java	Wed May 23 16:09:59 2012 -0700
@@ -356,26 +356,24 @@
     }
     
     private void setSortPos(int sortPos) {
-        if (! isSortingEnabled()) return;
-        
         this.sortPos = sortPos;
         updateSortGrid();
     }
     
     private void updateSortGrid() {
-        // we do not support sorting in embedded devices
-        if (! isSortingEnabled()) return;
-        
         // Fixe for RT-14488
         if (this instanceof NestedTableColumnHeader) return;
         
-        isSortColumn = sortPos != -1;
-        
         getChildren().clear();
         getChildren().add(label);
         
+        // we do not support sorting in embedded devices
+        if (! isSortingEnabled()) return;
+        
         if (! isSortColumn) return;
         
+        isSortColumn = sortPos != -1;
+        
         final int sortColumnCount = getTableView().getSortOrder().size();
         boolean showSortOrderDots = sortPos <= 3 && sortColumnCount > 1;
         
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/VirtualFlow.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/VirtualFlow.java	Wed May 23 16:09:59 2012 -0700
@@ -785,7 +785,10 @@
      * parent.
      */
     @Override public void requestLayout() {
-        if (getScene() != null && !isNeedsLayout()) {
+        // isNeedsLayout() is commented out due to RT-21417. This does not
+        // appear to impact performance (indeed, it may help), and resolves the
+        // issue identified in RT-21417.
+        if (getScene() != null/* && !isNeedsLayout()*/) {
             getScene().addToDirtyLayoutList(this);
             setNeedsLayout(true);
         }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/caspian/caspian.css	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/caspian/caspian.css	Wed May 23 16:09:59 2012 -0700
@@ -731,6 +731,8 @@
     -fx-cursor: hand;
     -fx-content-display: LEFT;
     -fx-text-fill: -fx-text-background-color;
+    -fx-border-color: transparent;
+    -fx-border-width: 1px;
 }
 
 .hyperlink:visited {
--- a/javafx-ui-controls/src/javafx/scene/chart/NumberAxis.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/chart/NumberAxis.java	Wed May 23 16:09:59 2012 -0700
@@ -243,9 +243,9 @@
         final double upperBound = rangeProps[1];
         final double tickUnit = rangeProps[2];
         List<Number> tickValues =  new ArrayList<Number>();
-        if (lowerBound == upperBound) {
+        if (tickUnit <= 0 || lowerBound == upperBound) {
             tickValues.add(lowerBound);
-        } else if (getTickUnit() != 0) {
+        } else if (getTickUnit() > 0) {
             for (double major = lowerBound; major <= upperBound; major += tickUnit)  {
                 tickValues.add(major);
                 if(tickValues.size()>2000) {
@@ -255,7 +255,7 @@
                     break;
                 }
             }
-        }
+        } 
         return tickValues;
     }
 
@@ -270,14 +270,16 @@
         final double upperBound = getUpperBound();
         final double tickUnit = getTickUnit();
         final double minorUnit = tickUnit/getMinorTickCount();
-        for (double major = lowerBound; major < upperBound; major += tickUnit)  {
-            for (double minor=major+minorUnit; minor < (major+tickUnit); minor += minorUnit) {
-                minorTickMarks.add(minor);
-                if(minorTickMarks.size()>10000) {
-                    // This is a ridiculous amount of major tick marks, something has probably gone wrong
-                    System.err.println("Warning we tried to create more than 10000 minor tick marks on a NumberAxis. " +
-                            "Lower Bound=" + getLowerBound() + ", Upper Bound=" + getUpperBound() + ", Tick Unit=" + tickUnit);
-                    break;
+        if (getTickUnit() > 0) {
+            for (double major = lowerBound; major < upperBound; major += tickUnit)  {
+                for (double minor=major+minorUnit; minor < (major+tickUnit); minor += minorUnit) {
+                    minorTickMarks.add(minor);
+                    if(minorTickMarks.size()>10000) {
+                        // This is a ridiculous amount of major tick marks, something has probably gone wrong
+                        System.err.println("Warning we tried to create more than 10000 minor tick marks on a NumberAxis. " +
+                                "Lower Bound=" + getLowerBound() + ", Upper Bound=" + getUpperBound() + ", Tick Unit=" + tickUnit);
+                        break;
+                    }
                 }
             }
         }
--- a/javafx-ui-controls/src/javafx/scene/control/ComboBox.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/control/ComboBox.java	Wed May 23 16:09:59 2012 -0700
@@ -64,11 +64,12 @@
  * exceedingly long.
  * 
  * <p>As with ListView, it is possible to modify the 
- * {@link javafx.scene.control.SelectionModel SelectionModel} that is used, 
- * although this is likely to be rarely changed. The default
- * SelectionModel used in ComboBox is a {@link SingleSelectionModel}, but this
- * can be switched out by developers to instead allow for multiple selection to 
- * occur, or to alter the behavior of the various methods provided in these APIs.
+ * {@link javafx.scene.control.SelectionModel selection model} that is used, 
+ * although this is likely to be rarely changed. This is because the ComboBox
+ * enforces the need for a {@link javafx.scene.control.SingleSelectionModel} 
+ * instance, and it is not likely that there is much need for alternate 
+ * implementations. Nonetheless, the option is there should use cases be found 
+ * for switching the selection model.
  * 
  * <p>As the ComboBox internally renders content with a ListView, API exists in
  * the ComboBox class to allow for a custom cell factory to be set. For more
@@ -235,6 +236,12 @@
                 updateEditor();
             }
         });
+        
+        converterProperty().addListener(new InvalidationListener() {
+            @Override public void invalidated(Observable o) {
+                updateBindings();
+            }
+        });
     }
     
  
@@ -385,18 +392,35 @@
      *                                                                         *
      **************************************************************************/        
 
+    private FocusableTextField textField;
+    
     private void updateEditor() {
         if (editor == null) {
             editor = new ReadOnlyObjectWrapper<TextField>(this, "editor");
         }
         
         if (isEditable()) {
-            editor.set(new FocusableTextField());
+            textField = new FocusableTextField();
+            updateBindings();
+            editor.set(textField);
         } else {
+            textField = null;
             editor.set(null);
         }
     }
     
+    private void updateBindings() {
+        if (textField == null) return;
+        
+        // remove bindings if any exist
+        textField.promptTextProperty().unbindBidirectional(promptTextProperty());
+//        textField.textProperty().unbindBidirectional(valueProperty());
+        
+        // update bindings with new converter
+        textField.promptTextProperty().bindBidirectional(promptTextProperty());
+//        textField.textProperty().bindBidirectional(valueProperty(), getConverter());
+    }
+    
     /***************************************************************************
      *                                                                         *
      * Stylesheet Handling                                                     *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledImplTest.css	Wed May 23 16:09:59 2012 -0700
@@ -0,0 +1,2 @@
+.menu-button .label { -fx-opacity: 50%;}
+
--- a/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledImplTest.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledImplTest.java	Wed May 23 16:09:59 2012 -0700
@@ -128,7 +128,7 @@
 
         Collection<Configuration[]> data = new ArrayList<Configuration[]>();
         
-        List<StyleableProperty> styleables = LabeledImpl.impl_CSS_STYLEABLES();
+        List<StyleableProperty> styleables = LabeledImpl.StyleableProperties.STYLEABLES_TO_MIRROR;
         for(StyleableProperty styleable : styleables) {
             
             // LabeledImpl doesn't track -fx-skin since the Labeled
--- a/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledImplTestOther.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/LabeledImplTestOther.java	Wed May 23 16:09:59 2012 -0700
@@ -16,17 +16,18 @@
 import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Cursor;
-import javafx.scene.control.ContentDisplay;
-import javafx.scene.control.Label;
-import javafx.scene.control.Labeled;
-import javafx.scene.control.OverrunStyle;
+import javafx.scene.Scene;
+import javafx.scene.control.*;
 import javafx.scene.effect.BlendMode;
 import javafx.scene.effect.ColorAdjustBuilder;
+import javafx.scene.effect.DropShadowBuilder;
 import javafx.scene.image.Image;
 import javafx.scene.image.ImageView;
+import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
 import javafx.scene.text.Font;
 import javafx.scene.text.TextAlignment;
+import javafx.stage.Stage;
 import javax.swing.GroupLayout;
 
 import org.junit.runner.RunWith;
@@ -55,4 +56,33 @@
         assertEquals(labeled.getGraphic(), labeledImpl.getGraphic());
     }
 
+    @Test 
+    public void test_RT_21617() {
+        
+        MenuButton mb = new MenuButton();
+        mb.setText("SomeText"); 
+        MenuButtonSkin mbs = new MenuButtonSkin(mb);
+        mb.setSkin(mbs);
+         
+        mb.setTranslateX(100);mb.setTranslateY(100); 
+        
+        Scene scene = new Scene(mb, 300, 300); 
+        scene.getStylesheets().add(LabeledImplTestOther.class.getResource("LabeledImplTest.css").toExternalForm());
+        Stage stage = new Stage();
+        stage.setScene(scene); 
+        stage.show(); 
+        
+        
+        LabeledImpl labeledImpl = (LabeledImpl)mbs.lookup(".label");
+        assertNotNull(labeledImpl);
+        // LabeledImpl should not mirror the translateX/Y of the MenuButton
+        assertEquals(100, mb.getTranslateX(), 0.00001);
+        assertEquals(0, labeledImpl.getTranslateX(), 0.00001);
+        assertEquals(100, mb.getTranslateY(), 0.00001);
+        assertEquals(0, labeledImpl.getTranslateY(), 0.00001);
+        // opacity set to 50% in LabeledImplTest.css
+        assertEquals(1, mb.getOpacity(), 0.00001);
+        assertEquals(.5, labeledImpl.getOpacity(), 0.00001);
+    }
+    
 }
--- a/javafx-ui-controls/test/javafx/scene/control/PaginationTest.java	Wed May 23 10:52:00 2012 -0700
+++ b/javafx-ui-controls/test/javafx/scene/control/PaginationTest.java	Wed May 23 16:09:59 2012 -0700
@@ -229,6 +229,23 @@
         assertEquals(5, pagination.getCurrentPageIndex());
     }
 
+    @Test public void pageCountIsLessThanMaxPageIndicatorCount_RT21660() {
+        pagination.setPageCount(5);
+        root.setPrefSize(400, 400);
+        root.getChildren().add(pagination);
+        show();
+        
+        pagination.setCurrentPageIndex(4);
+        tk.firePulse();
+        assertTrue(pagination.isFocused());
+
+        KeyEventFirer keyboard = new KeyEventFirer(pagination);
+        keyboard.doRightArrowPress();
+        tk.firePulse();
+
+        assertEquals(4, pagination.getCurrentPageIndex());
+    }
+    
     public VBox createPage(int pageIndex) {
         VBox box = new VBox(5);
         int page = pageIndex * 10;