changeset 1444:aa283b2f20ad

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/2.2/MASTER/jfx/rt
author Kinsley Wong
date Thu, 12 Jul 2012 16:27:13 -0700
parents f28a395961d2 374f5352788f
children d12adf6ea5d5
files
diffstat 19 files changed, 562 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-designtime/src/javafx/scene/layout/GridPaneDesignInfo.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-designtime/src/javafx/scene/layout/GridPaneDesignInfo.java	Thu Jul 12 16:27:13 2012 -0700
@@ -75,8 +75,8 @@
         final double gridPaneWidth = pane.snapSize(pane.getWidth()) - (left + right);
 
         // Compute row height
-        double[] rowHeights = pane.getRowHeights();
-        if (rowHeights == null || rowHeights.length == 0) {
+        double[] rowHeights = pane.getRowHeights();        
+        if (rowHeights == null || rowHeights.length == 0 || rowHeights.length != getRowCount(pane)) {
             rowHeights = new double[] {0};
             rowIndex = 0;
         }
@@ -97,7 +97,7 @@
 
         // Compute column width
         double[] columnWidths = pane.getColumnWidths();
-        if (columnWidths == null || columnWidths.length == 0) {
+        if (columnWidths == null || columnWidths.length == 0 || columnWidths.length != getColumnCount(pane)) {
             columnWidths = new double[] {0};
             columnIndex = 0;
         }
--- a/javafx-ui-charts/src/javafx/scene/chart/BarChart.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/BarChart.java	Thu Jul 12 16:27:13 2012 -0700
@@ -256,7 +256,9 @@
              item.getNode().getStyleClass().add("negative");
          } else if (currentVal < 0 && barVal > 0) { // going from negative to positive
              // remove style class negative
-             item.getNode().getStyleClass().add("negative");
+             // RT-21164 upside down bars: was adding "negative" styleclass
+             // instead of removing it; when going from negative to positive
+             item.getNode().getStyleClass().remove("negative");
          }
     }
     
@@ -314,6 +316,12 @@
             if (shouldAnimate()) {
                 animateDataAdd(item, bar);
             } else {
+                // RT-21164 check if bar value is negative to add "negative" style class 
+                double barVal = (orientation == Orientation.VERTICAL) ? ((Number)item.getYValue()).doubleValue() :
+                        ((Number)item.getXValue()).doubleValue();
+                if (barVal < 0) {
+                    bar.getStyleClass().add("negative");
+                }
                 getPlotChildren().add(bar);
             }
         }
--- a/javafx-ui-charts/src/javafx/scene/chart/Chart.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/Chart.java	Thu Jul 12 16:27:13 2012 -0700
@@ -62,6 +62,9 @@
 
     // -------------- PRIVATE FIELDS -----------------------------------------------------------------------------------
 
+    private static final int MIN_WIDTH_TO_LEAVE_FOR_CHART_CONTENT = 200;
+    private static final int MIN_HEIGHT_TO_LEAVE_FOR_CHART_CONTENT = 150;
+
     /** Title Label */
     private final Label titleLabel = new Label();
     /**
@@ -169,12 +172,7 @@
      */
     private final BooleanProperty legendVisible = new StyleableBooleanProperty(true) {
         @Override protected void invalidated() {
-            boolean vis = get();
-            Node legend = getLegend();
-            if(legend != null) {
-                legend.setVisible(vis);
-                requestLayout();
-            }
+            requestLayout();
         }
             
         @Override
@@ -340,28 +338,48 @@
         }
         // layout legend
         final Node legend = getLegend();
-        if (legend != null && isLegendVisible()) {
-            if (getLegendSide().equals(Side.TOP)) {
-                final double legendHeight = snapSize(legend.prefHeight(width-left-right));
-                final double legendWidth = snapSize(legend.prefWidth(-1));
-                legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), top, legendWidth, legendHeight);
-                top += legendHeight;
-            } else if (getLegendSide().equals(Side.BOTTOM)) {
-                final double legendHeight = snapSize(legend.prefHeight(width-left-right));
-                final double legendWidth = snapSize(legend.prefWidth(-1));
-                legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), height-bottom-legendHeight, legendWidth, legendHeight);
-                bottom += legendHeight;
-            } else if (getLegendSide().equals(Side.LEFT)) {
-                final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
-                final double legendHeight = snapSize(legend.prefHeight(-1));
-                legend.resizeRelocate(left,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
-                left += legendWidth;
-            } else if (getLegendSide().equals(Side.RIGHT)) {
-                final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
-                final double legendHeight = snapSize(legend.prefHeight(-1));
-                legend.resizeRelocate(width-right-legendWidth,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
-                right += legendWidth;
+        if (legend != null) {
+            boolean shouldShowLegend = isLegendVisible();
+            if (shouldShowLegend) {
+                if (getLegendSide().equals(Side.TOP)) {
+                    final double legendHeight = snapSize(legend.prefHeight(width-left-right));
+                    final double legendWidth = snapSize(legend.prefWidth(-1));
+                    legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), top, legendWidth, legendHeight);
+                    if ((height - bottom - top - legendHeight) < MIN_HEIGHT_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        top += legendHeight;
+                    }
+                } else if (getLegendSide().equals(Side.BOTTOM)) {
+                    final double legendHeight = snapSize(legend.prefHeight(width-left-right));
+                    final double legendWidth = snapSize(legend.prefWidth(-1));
+                    legend.resizeRelocate(left + (((width - left - right)-legendWidth)/2), height-bottom-legendHeight, legendWidth, legendHeight);
+                    if ((height - bottom - top - legendHeight) < MIN_HEIGHT_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        bottom += legendHeight;
+                    }
+                } else if (getLegendSide().equals(Side.LEFT)) {
+                    final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
+                    final double legendHeight = snapSize(legend.prefHeight(-1));
+                    legend.resizeRelocate(left,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
+                    if ((width - left - right - legendWidth) < MIN_WIDTH_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        left += legendWidth;
+                    }
+                } else if (getLegendSide().equals(Side.RIGHT)) {
+                    final double legendWidth = snapSize(legend.prefWidth(height-top-bottom));
+                    final double legendHeight = snapSize(legend.prefHeight(-1));
+                    legend.resizeRelocate(width-right-legendWidth,top +(((height-top-bottom)-legendHeight)/2),legendWidth,legendHeight);
+                    if ((width - left - right - legendWidth) < MIN_WIDTH_TO_LEAVE_FOR_CHART_CONTENT) {
+                        shouldShowLegend = false;
+                    } else {
+                        right += legendWidth;
+                    }
+                }
             }
+            legend.setVisible(shouldShowLegend);
         }
         // whats left is for the chart content
         chartContent.resizeRelocate(left,top,width-left-right,height-top-bottom);
--- a/javafx-ui-charts/src/javafx/scene/chart/LineChart.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/LineChart.java	Thu Jul 12 16:27:13 2012 -0700
@@ -57,7 +57,7 @@
 import com.sun.javafx.css.StyleableBooleanProperty;
 import com.sun.javafx.css.StyleableProperty;
 import com.sun.javafx.css.converters.BooleanConverter;
-import java.util.Collections;
+import java.util.*;
 
 /**
  * Line Chart plots a line connecting the data points in a series. The data points
@@ -259,8 +259,12 @@
                 }
             } else if (itemIndex == 0 && series.getDataSize() > 1) {
                 animate = true;
-                item.setXValue(series.getData().get(0).getXValue());
-                item.setYValue(series.getData().get(0).getYValue());
+                Iterator<Data<X,Y>> iter = getDisplayedDataIterator(series);
+                if (iter.hasNext()) { // get first data value
+                    Data<X,Y> d = iter.next();
+                    item.setXValue(d.getXValue());
+                    item.setYValue(d.getYValue());
+                }
             } else if (itemIndex == (series.getDataSize() - 1) && series.getDataSize() > 1) {
                 animate = true;
                 int last = series.getData().size() - 1;
--- a/javafx-ui-charts/src/javafx/scene/chart/PieChart.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/PieChart.java	Thu Jul 12 16:27:13 2012 -0700
@@ -24,6 +24,7 @@
  */
 package javafx.scene.chart;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -52,14 +53,10 @@
 import javafx.geometry.Side;
 import javafx.scene.Node;
 import javafx.scene.layout.Region;
-import javafx.scene.shape.Arc;
-import javafx.scene.shape.ArcTo;
-import javafx.scene.shape.ArcType;
-import javafx.scene.shape.ClosePath;
-import javafx.scene.shape.LineTo;
-import javafx.scene.shape.MoveTo;
-import javafx.scene.shape.Path;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.*;
 import javafx.scene.text.Text;
+import javafx.scene.transform.Scale;
 import javafx.util.Duration;
 
 import com.sun.javafx.charts.Legend;
@@ -84,6 +81,7 @@
 public class PieChart extends Chart {
 
     // -------------- PRIVATE FIELDS -----------------------------------------------------------------------------------
+    private static final int MIN_PIE_RADIUS = 25;
     private int defaultColorIndex = 0;
     private static final double LABEL_TICK_GAP = 6;
     private static final double LABEL_BALL_RADIUS = 2;
@@ -474,7 +472,9 @@
         double[] labelsX = null;
         double[] labelsY = null;
         double[] labelAngles = null;
+        double labelScale = 1;
         ArrayList<LabelLayoutInfo> fullPie = null;
+        boolean shouldShowLabels = true;
         if(getLabelsVisible()) {
             labelsX = new double[getDataSize()];
             labelsY = new double[getDataSize()];
@@ -483,17 +483,20 @@
             int index = 0;
             double start = getStartAngle();
             for (Data item = begin; item != null; item = item.next) {
+                // remove any scale on the text node
+                item.textNode.getTransforms().clear();
+
                 double size = (isClockwise()) ? (-scale * Math.abs(item.getCurrentPieValue())) : (scale * Math.abs(item.getCurrentPieValue()));
                 labelAngles[index] = normalizeAngle(start + (size / 2));
-                final boolean isLeftSide = !(labelAngles[index] > -90 && labelAngles[index] < 90);
                 final double sproutX = calcX(labelAngles[index], getLabelLineLength(), 0);
                 final double sproutY = calcY(labelAngles[index], getLabelLineLength(), 0);
                 labelsX[index] = sproutX;
                 labelsY[index] = sproutY;
-                if (sproutX > 0) { // on left
+                if (sproutX < 0) { // on left
                     minX = Math.min(minX, sproutX-item.textNode.getLayoutBounds().getWidth()-LABEL_TICK_GAP);
                 } else { // on right
                     maxX = Math.max(maxX, sproutX+item.textNode.getLayoutBounds().getWidth()+LABEL_TICK_GAP);
+
                 }
                 if (sproutY > 0) { // on bottom
                     maxY = Math.max(maxY, sproutY+item.textNode.getLayoutBounds().getMaxY());
@@ -506,16 +509,41 @@
             double xPad = (Math.max(Math.abs(minX), Math.abs(maxX))) * 2;
             double yPad = (Math.max(Math.abs(minY), Math.abs(maxY))) * 2;
             pieRadius = Math.min(contentWidth - xPad, contentHeight - yPad) / 2;
-        } else {
+            // check if this makes the pie too small
+            if (pieRadius < MIN_PIE_RADIUS ) {
+                // calculate scale for text to fit labels in
+                final double roomX = contentWidth-MIN_PIE_RADIUS-MIN_PIE_RADIUS;
+                final double roomY = contentHeight-MIN_PIE_RADIUS-MIN_PIE_RADIUS;
+                labelScale = Math.min(
+                        roomX/xPad,
+                        roomY/yPad
+                );
+                // hide labels if pie radius is less than minimum
+                if ((begin == null && labelScale < 0.7) || ((begin.textNode.getFont().getSize()*labelScale) < 9)) {
+                    shouldShowLabels = false;
+                    labelScale = 1;
+                } else {
+                    // set pieRadius to minimum
+                    pieRadius = MIN_PIE_RADIUS;
+                    // apply scale to all label positions
+                    for(int i=0; i< labelsX.length; i++) {
+                        labelsX[i] =  labelsX[i] * labelScale;
+                        labelsY[i] =  labelsY[i] * labelScale;
+                    }
+                }
+            }
+        }
+
+        if(!shouldShowLabels) {
             pieRadius = Math.min(contentWidth,contentHeight) / 2;
         }
-      
+
         if (getChartChildren().size() > 0) {
             int index = 0;
             for (Data item = begin; item != null; item = item.next) {
                 // layout labels for pie slice
-                item.textNode.setVisible(getLabelsVisible());
-                if (getLabelsVisible()) {
+                item.textNode.setVisible(shouldShowLabels);
+                if (shouldShowLabels) {
                     double size = (isClockwise()) ? (-scale * Math.abs(item.getCurrentPieValue())) : (scale * Math.abs(item.getCurrentPieValue()));
                     final boolean isLeftSide = !(labelAngles[index] > -90 && labelAngles[index] < 90);
                     
@@ -532,13 +560,26 @@
                     LabelLayoutInfo info = new LabelLayoutInfo(sliceCenterEdgeX,
                             sliceCenterEdgeY,lineEndX, lineEndY, xval, yval, item.textNode, Math.abs(size));
                     fullPie.add(info);
+
+                    // set label scales
+                    if (labelScale < 1) {
+                        item.textNode.getTransforms().add(
+                            new Scale(
+                                    labelScale, labelScale,
+                                    isLeftSide ? item.textNode.getLayoutBounds().getWidth() : 0,
+//                                    0,
+                                    0
+                            )
+                        );
+                    }
                 }
                 index++;
             }
 
              // Check for collision and resolve by hiding the label of the smaller pie slice
             resolveCollision(fullPie);
-            
+
+            // update/draw pie slices
             double sAngle = getStartAngle();
             for (Data item = begin; item != null; item = item.next) {
              Node node = item.getNode();
--- a/javafx-ui-charts/src/javafx/scene/chart/XYChart.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-charts/src/javafx/scene/chart/XYChart.java	Thu Jul 12 16:27:13 2012 -0700
@@ -169,8 +169,9 @@
             if(old != null) {
                 old.removeListener(seriesChanged);
                 // Set animated to false so we don't animate both remove and add
-                // at the same time. RT-14163
-                if (old.size() > 0) {
+                // at the same time. RT-14163 
+                // RT-21295 - disable animated only when current is also not null. 
+                if (current != null && old.size() > 0) {
                     saveAnimationState = (old.get(0).getChart().getAnimated()) ? 1 : 2;
                     old.get(0).getChart().setAnimated(false);
                 }
--- a/javafx-ui-common/src/com/sun/javafx/css/CssError.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/CssError.java	Thu Jul 12 16:27:13 2012 -0700
@@ -25,7 +25,11 @@
 
 package com.sun.javafx.css;
 
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
 import java.net.URL;
+import javafx.scene.Node;
+import javafx.scene.Scene;
 
 /**
  * Encapsulate information about the source and nature of errors encountered
@@ -33,15 +37,54 @@
  */
 public class CssError {
  
-    /** The error message from the CSS code */
+    // RT-20643 - hold a ref so CssError doesn't leak Scene.
+    private static Reference<Scene> SCENE_REF;
+            
+    /** 
+     * Set the static scene variable. This scene will be set on all CssErrors
+     * generated after the call is made. The argument may be null. Null should
+     * be passed when the code exits a method from which CssErrors may be 
+     * created. This is intended internal use and should not be called from
+     * outside the css code.
+     */
+    public static void setCurrentScene(Scene scene) {
+        
+        // Treat as a no-op if noone cares about CssErrors
+        if (StyleManager.getInstance().getErrors() == null) return;
+        
+        if (scene != null) {
+            // don't make new ref for same scene
+            final Scene oldScene = SCENE_REF != null ? SCENE_REF.get() : null;
+            if (oldScene != scene) {
+                SCENE_REF = new WeakReference<Scene>(scene);
+            }
+        } else {
+            SCENE_REF = null;
+        }
+    }
+    
+    /** @return The error message from the CSS code. */
     public final String getMessage() {
         return message;
     }
-        
+
     public CssError(String message) {
         this.message = message;
+        // RT-20643        
+        this.sceneRef = SCENE_REF;
     }
     
+    /** 
+     * @return The Scene in which this error occurred, if known, or null.
+     */
+    public Scene getScene() {
+        return sceneRef != null ? sceneRef.get() : null;
+    }
+    
+    // RT-20643 - track the scene that this error belongs to       
+    // Note that CssError has the potential to leak Scene so the Scene
+    // variable is held as a Reference.
+    private final Reference<Scene> sceneRef;
     protected final String message;
 
     @Override
@@ -125,14 +168,14 @@
     public final static class PropertySetError extends CssError { 
         
         public PropertySetError(StyleableProperty styleableProperty, 
-                Styleable styleable, String message) {
+                Node node, String message) {
             super(message);
             this.styleableProperty = styleableProperty;
-            this.styleable = styleable;
+            this.node = node;
         }
         
-        public Styleable getStyleable() {
-            return styleable;
+        public Node getNode() {
+            return node;
         }
         
         public StyleableProperty getProperty() {
@@ -140,7 +183,7 @@
         }
         
         private final StyleableProperty styleableProperty;
-        private final Styleable styleable;
+        private final Node node;
         
     }
 }     
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleHelper.java	Thu Jul 12 16:27:13 2012 -0700
@@ -303,7 +303,8 @@
         // member will be null. If this is a local cache, then this member
         // will point to the shared cache for the same states.
         //
-        private final CacheEntry sharedCache;
+        // RT-23079 - weakly reference the shared CacheEntry
+        private final Reference<CacheEntry> sharedCacheRef;
 
         private CacheEntry(long[] states) {
             this(states, null);
@@ -312,16 +313,20 @@
         private CacheEntry(long[] states, CacheEntry sharedCache) {
             this.states = states;
             this.values = new HashMap<String,CalculatedValue>();
-            this.sharedCache = sharedCache;
+            this.sharedCacheRef = new WeakReference<CacheEntry>(sharedCache);
         }
 
         private CalculatedValue get(String property) {
+            
             CalculatedValue cv = null;
             if (values.isEmpty() == false) {
                 cv = values.get(property);
             }
-            if (cv == null && sharedCache != null) {
-                cv = sharedCache.values.get(property);
+            if (cv == null && sharedCacheRef != null) {
+                final CacheEntry ce = sharedCacheRef.get();
+                if (ce != null) cv = ce.values.get(property);
+                // if referent is null, we should skip the value. 
+                else cv = SKIP; 
             }
             return cv;
         }
@@ -334,7 +339,7 @@
             // then use local cache if the font origin is inline or user and
             // the value was calculated from a relative size unit. 
             final boolean isLocal = 
-                (sharedCache == null
+                (sharedCacheRef == null
                     || cv.origin == Origin.INLINE
                     || cv.origin == Origin.USER)
                 || (cv.isRelative &&
@@ -343,9 +348,13 @@
             
             if (isLocal) {
                 values.put(property, cv);
-            } else if (sharedCache.values.containsKey(property) == false) {
-                // don't override value already in shared cache.
-                sharedCache.values.put(property, cv);
+            } else {
+                // if isLocal is false, then sharedCacheRef cannot be null. 
+                final CacheEntry ce = sharedCacheRef.get();
+                if (ce != null && ce.values.containsKey(property) == false) {
+                    // don't override value already in shared cache.
+                    ce.values.put(property, cv);
+                }
             }
         }
 
@@ -435,7 +444,7 @@
         final int max = entries.size();
         for (int n=0; n<max; n++) {
             CacheEntry entry = entries.get(n);
-            assert (entry.sharedCache != null);
+            assert (entry.sharedCacheRef != null);
             entry.values.clear();
             entry.font = null;
         }
@@ -738,15 +747,23 @@
         //
                 
         final CacheEntry cacheEntry = getCacheEntry(node, pseudoClassStates);
-        if (cacheEntry == null) {
+        if (cacheEntry == null 
+            || (cacheEntry.sharedCacheRef != null 
+                && cacheEntry.sharedCacheRef.get() == null)) {
             // If cacheEntry is null, then the StyleManager Cache from which
             // this StyleHelper was created has been blown away and this
             // StyleHelper is no good. If this is the case, we need to tell
             // this node to reapply CSS
+            //
+            // RT-23079 - if this is local cache, then the sharedCacheRef 
+            // will not be null. If sharedCacheRef is not null, but its 
+            // referent is null, then the styleMap in the StylesheetContainer
+            // has been cleared and we're working with a cache that is no good.
+            // 
             node.impl_reapplyCSS();
             return;
         }
-
+        
         //
         // if this node has a style map, then we'll populate it.
         // 
@@ -755,7 +772,7 @@
         //
         // If someone is watching the styles, then we have to take the slow path.
         //
-        boolean fastpath = styleMap == null;
+        boolean fastpath = styleMap == null && inlineStyles == null;
         
         if (cacheEntry.font == null) {
             final CalculatedValue font = 
@@ -782,6 +799,9 @@
         // Used in the for loop below, and a convenient place to stop when debugging.
         final int max = styleables.size();
 
+        // RT-20643
+        CssError.setCurrentScene(node.getScene());
+        
         // For each property that is settable, we need to do a lookup and
         // transition to that value.
         for(int n=0; n<max; n++) {
@@ -854,11 +874,11 @@
                 calculatedValue = lookup(node, styleable, isUserSet, states, 
                         inlineStyles, node, cacheEntry, styleList);
 
-//                if (fastpath) {
+                if (fastpath) {
                     // if userStyles is null and calculatedValue was null,
                     // then the calculatedValue didn't come from the cache
                     cacheEntry.put(property, calculatedValue);
-//                }
+                }
 
             }
 
@@ -883,7 +903,7 @@
                     List<CssError> errors = null;
                     if ((errors = StyleManager.getInstance().getErrors()) != null) {
                         final String msg = String.format("Failed to set css [%s] due to %s\n", styleable, e.getMessage());
-                        final CssError error = new CssError.PropertySetError(styleable, node.impl_getStyleable(), msg);
+                        final CssError error = new CssError.PropertySetError(styleable, node, msg);
                         errors.add(error);
                     }
                     // TODO: use logger here
@@ -894,6 +914,10 @@
                 }
 
             }
+        
+        // RT-20643
+        CssError.setCurrentScene(null);
+
         // If the list weren't empty, we'd worry about animations at this
         // point. TODO need to implement animation trickery here
     }
@@ -1064,7 +1088,7 @@
                     final String msg = formatExceptionMessage(node, styleable, style.getStyle(), cce);
                     List<CssError> errors = null;
                     if ((errors = StyleManager.getInstance().getErrors()) != null) {
-                        final CssError error = new CssError.PropertySetError(styleable, node.impl_getStyleable(), msg);
+                        final CssError error = new CssError.PropertySetError(styleable, node, msg);
                         errors.add(error);
                     }
                     if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
@@ -1512,7 +1536,7 @@
                 final String msg = formatUnresolvedLookupMessage(node, styleable, style.getStyle(),resolved);
                 List<CssError> errors = null;
                 if ((errors = StyleManager.getInstance().getErrors()) != null) {
-                    final CssError error = new CssError.PropertySetError(styleable, node.impl_getStyleable(), msg);
+                    final CssError error = new CssError.PropertySetError(styleable, node, msg);
                     errors.add(error);
                 }
                 if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
@@ -1526,7 +1550,7 @@
                 final String msg = formatExceptionMessage(node, styleable, style.getStyle(), iae);
                 List<CssError> errors = null;
                 if ((errors = StyleManager.getInstance().getErrors()) != null) {
-                    final CssError error = new CssError.PropertySetError(styleable, node.impl_getStyleable(), msg);
+                    final CssError error = new CssError.PropertySetError(styleable, node, msg);
                     errors.add(error);
                 }
                 if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
@@ -1539,7 +1563,7 @@
                 final String msg = formatExceptionMessage(node, styleable, style.getStyle(), npe);
                 List<CssError> errors = null;
                 if ((errors = StyleManager.getInstance().getErrors()) != null) {
-                    final CssError error = new CssError.PropertySetError(styleable, node.impl_getStyleable(), msg);
+                    final CssError error = new CssError.PropertySetError(styleable, node, msg);
                     errors.add(error);
                 }
                 if (LOGGER.isLoggable(PlatformLogger.WARNING)) {
--- a/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/css/StyleManager.java	Thu Jul 12 16:27:13 2012 -0700
@@ -636,16 +636,31 @@
     
     /**
      * Add a user agent stylesheet, possibly overriding styles in the default
-     * user agent stylesheet. The node argument must be an instance of Control.
+     * user agent stylesheet.
      *
      * @param fname The file URL, either relative or absolute, as a String.
      */
     public void addUserAgentStylesheet(String fname) {
+        addUserAgentStylesheet(null, fname);
+    }
+    
+    /**
+     * Add a user agent stylesheet, possibly overriding styles in the default
+     * user agent stylesheet.
+     * @param scene Only used in CssError for tracking back to the scene that loaded the stylesheet
+     * @param fname  The file URL, either relative or absolute, as a String.
+     */
+    // For RT-20643    
+    public void addUserAgentStylesheet(Scene scene, String fname) {
                 
         // nothing to add
         if (fname == null ||  fname.trim().isEmpty()) return;
 
         if (userAgentStylesheetMap.containsKey(fname) == false) {
+
+            // RT-20643
+            CssError.setCurrentScene(scene);
+            
             Stylesheet ua_stylesheet = loadStylesheet(fname);
             ua_stylesheet.setOrigin(Stylesheet.Origin.USER_AGENT);
             userAgentStylesheetMap.put(fname, ua_stylesheet);
@@ -653,6 +668,9 @@
             if (ua_stylesheet != null) {
                 userAgentStylesheetsChanged();                
             }
+            
+            // RT-20643
+            CssError.setCurrentScene(null);
         }
 
     }
@@ -663,15 +681,31 @@
      * @param fname The file URL, either relative or absolute, as a String.
      */
     public void setDefaultUserAgentStylesheet(String fname) {
+        setDefaultUserAgentStylesheet(null, fname);
+    }
+    
+    /**
+     * Set the default user agent stylesheet
+     * @param scene Only used in CssError for tracking back to the scene that loaded the stylesheet
+     * @param fname  The file URL, either relative or absolute, as a String.
+     */
+    // For RT-20643
+    public void setDefaultUserAgentStylesheet(Scene scene, String fname) {
 
         if (fname == null || fname.trim().isEmpty())
             throw new IllegalArgumentException("null arg fname");
 
+        // RT-20643
+        CssError.setCurrentScene(scene);
+        
         Stylesheet ua_stylesheet = loadStylesheet(fname);
         if (ua_stylesheet != null) {
             ua_stylesheet.setOrigin(Stylesheet.Origin.USER_AGENT);
             setDefaultUserAgentStylesheet(ua_stylesheet);
         } 
+        
+        // RT-20643
+        CssError.setCurrentScene(null);
 
     }
     
@@ -811,6 +845,9 @@
         // if there are no stylesheets, then they were probably all removed.
         if (scene.getStylesheets().size() == 0) return;
 
+        // RT-20643
+        CssError.setCurrentScene(scene);
+        
         // create the stylesheets, one per URL supplied
         final Collection<Stylesheet> stylesheets = new ArrayList<Stylesheet>();
         for (int i = 0; i < scene.getStylesheets().size(); i++) {
@@ -830,6 +867,9 @@
             }
         }
 
+        // RT-20643
+        CssError.setCurrentScene(scene);
+        
         // Look up existing user stylesheets and add new stylesheets.
         // We defer creation of the containerMap until needed
         if (containerMap == null) containerMap =
@@ -1084,6 +1124,9 @@
             
             final List<ParentStylesheetContainer> list = new ArrayList<ParentStylesheetContainer>();
             
+            // RT-20643 
+            CssError.setCurrentScene(parent.getScene());
+            
             for (int n=0, nMax=parentStylesheets.size(); n<nMax; n++) {
                 final String fname = parentStylesheets.get(n);
                 ParentStylesheetContainer container = null;
@@ -1110,6 +1153,8 @@
                 }
                 if (container != null) list.add(container);
             }
+            // RT-20643 
+            CssError.setCurrentScene(null);
             
             return list;
         }
@@ -1315,7 +1360,7 @@
                 for(int n=0; n<nElements; n++) newKey.styleClass.add(styleClass.get(n));
                 newKey.indices = hasParentStylesheets ? indicesOfParentsWithStylesheets : null;
                 
-                cache = new Cache(this, rules, pseudoclassStateMask, impactsChildren);
+                cache = new Cache(rules, pseudoclassStateMask, impactsChildren);
                 cacheMap.put(newKey, cache);
                 
                 // RT-22565: remember where this cache is used if there are 
@@ -1331,7 +1376,7 @@
             // Return the style helper looked up by the cache. The cache will
             // create a style helper if necessary (and possible), so we don't
             // have to worry about that part.
-            StyleMap smap = cache.getStyleMap(node);
+            StyleMap smap = cache.getStyleMap(this, node);
             if (smap == null) return null;
             
             StyleHelper helper = 
@@ -1347,12 +1392,26 @@
     }
 
     private ObservableList<CssError> errors = null;
+    /** 
+     * Errors that may have occurred during css processing. 
+     * This list is null until errorsProperty() is called.
+     * @return 
+     */
     public ObservableList<CssError> errorsProperty() {
         if (errors == null) {
             errors = FXCollections.observableArrayList();
         }
         return errors;
     }
+    
+    /** 
+     * Errors that may have occurred during css processing.
+     * This list is null until errorsProperty() is called and is used 
+     * internally to figure out whether or  not anyone is interested in 
+     * receiving CssError.
+     * Not meant for general use - call errorsProperty() instead. 
+     * @return 
+     */
     public ObservableList<CssError> getErrors() {
         return errors;
     }
@@ -1376,7 +1435,7 @@
      * Creates and caches maps of styles, reusing them as often as practical.
      */
     private static class Cache {
-        private final StylesheetContainer owner;
+
         // this must be initialized to the appropriate possible rules when
         // the helper cache is created by the StylesheetContainer
         private final List<Rule> rules;
@@ -1384,15 +1443,14 @@
         private final boolean impactsChildren;
         private final Map<Long, StyleMap> cache;
         
-        Cache(StylesheetContainer owner, List<Rule> rules, long pseudoclassStateMask, boolean impactsChildren) {
-            this.owner = owner;
+        Cache(List<Rule> rules, long pseudoclassStateMask, boolean impactsChildren) {
             this.rules = rules;
             this.pseudoclassStateMask = pseudoclassStateMask;
             this.impactsChildren = impactsChildren;
             this.cache = new HashMap<Long, StyleMap>();
         }
 
-        private StyleMap getStyleMap(Node node) {
+        private StyleMap getStyleMap(StylesheetContainer owner, Node node) {
 
             // If this set of rules (which may be empty) impacts children,
             // then this node will get a StyleHelper.
--- a/javafx-ui-common/src/javafx/scene/doc-files/cssref.html	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/doc-files/cssref.html	Thu Jul 12 16:27:13 2012 -0700
@@ -282,6 +282,7 @@
               <li><a href="#checkbox">CheckBox</a></li>
               <li><a href="#checkmenuitem">CheckMenuItem</a></li>
               <li><a href="#choicebox">ChoiceBox</a></li>
+              <li><a href="#colorpicker">ColorPicker</a></li>
               <li><a href="#combobox">ComboBox</a></li>
               <li><a href="#control">Control</a></li>
               <li><a href="#hyperlink">Hyperlink</a></li>
@@ -1481,7 +1482,7 @@
     <p>With looked-up colors you can refer to any other color property that is
       set on the current node or any of its parents. This is a very powerful
       feature, as it allows a generic palette of colors to be specified on the
-      scene then used thoughout the application. If you want tochange one of
+      scene then used thoughout the application. If you want to change one of
       those palette colors you can do so at any level in the scene tree and it
       will affect that node and all its decendents. Looked-up colors are not
       looked up until they are applied, so they are live and react to any style
@@ -3242,6 +3243,39 @@
         </ul>
       </li>
     </ul>
+    <h4><a name="colorpicker" id="colorpicker">ColorPicker</a></h4>
+    <p class="styleclass">Style class: color-picker</p>
+	<p>The ColorPicker control has all the properties and pseudo-classes of <a href="#comboboxbase">ComboBoxBase</a></p>
+    <table summary="property table" class="csspropertytable" cellpadding="2" cellspacing="1">
+      <thead>
+        <tr>
+          <th class="propertyname">CSS Property</th>
+          <th class="value">Values</th>
+          <th>Default</th>
+          <th>Comments</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td class="propertyname">-fx-color-label-visible</td>
+          <td class="value"><a href="#typesize" class="typelink">&lt;boolean&gt;</a></td>
+          <td>true</td>
+          <td>&nbsp;</td>
+        </tr>
+        <tr>
+          <td colspan="4" class="parents">Also has all properties of <a href="#control">Control</a></td>
+        </tr>
+      </tbody>
+    </table>
+    <h4>Substructure</h4>
+    <ul>
+	  <li>color display node  &mdash; Label</li>
+      <li>arrow-button - StackPane</li>
+	    <ul>
+		  <li>arrow &mdash; StackPane</li>
+	    </ul>
+	  </ul>
+    </ul>
     <h4><a name="combobox" id="combobox">ComboBox</a></h4>
     <p class="styleclass">Style class: combo-box</p>
     <p>The ComboBox control has all the properties and pseudo-classes of <a href="#comboboxbase">ComboBoxBase</a></p>
@@ -3456,6 +3490,12 @@
           <td>&nbsp;</td>
         </tr>
         <tr>
+          <td class="propertyname">-fx-ellipsis-string</td>
+          <td class="value"><a href="#typestring" class="typelink">&lt;string&gt;</a></td>
+          <td>...</td>
+          <td>&nbsp;</td>
+        </tr>
+        <tr>
           <td colspan="4" class="parents">Also has properties of <a href="#control">Control</a></td>
         </tr>
       </tbody>
@@ -3610,7 +3650,7 @@
           <td>&nbsp;</td>
         </tr>
         <tr>
-          <td class="propertyname">fx-page-information-visible:</td>
+          <td class="propertyname">-fx-page-information-visible:</td>
           <td class="value"><a href="#typesize" class="typelink">&lt;boolean&gt;</a></td>
           <td>true</td>
           <td>&nbsp;</td>
@@ -3650,6 +3690,42 @@
     <h4><a name="popupcontrol" id="popupcontrol">PopupControl</a></h4>
     <h4><a name="progressbar" id="progressbar">ProgressBar</a></h4>
     <p class="styleclass">Style class: progress-bar</p>
+    <table summary="property table" class="csspropertytable" cellpadding="2" cellspacing="1">
+      <thead>
+        <tr>
+          <th class="propertyname">CSS Property</th>
+          <th class="value">Values</th>
+          <th>Default</th>
+          <th>Comments</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td class="propertyname">-fx-indeterminate-bar-length</td>
+          <td class="value"><a href="#typenumber" class="typelink">&lt;number&gt;</a></td>
+          <td>60</td>
+          <td>&nbsp;</td>
+        </tr>
+        <tr>
+          <td class="propertyname">-fx-indeterminate-bar-escape</td>
+          <td class="value"><a href="#typesize" class="typelink">&lt;boolean&gt;</a></td>
+          <td>true</td>
+          <td>&nbsp;</td>
+        </tr>
+        <tr>
+          <td class="propertyname">-fx-indeterminate-bar-flip</td>
+          <td class="value"><a href="#typesize" class="typelink">&lt;boolean&gt;</a></td>
+          <td>true</td>
+          <td>&nbsp;</td>
+        </tr>
+        <tr>
+          <td class="propertyname">-fx-indeterminate-bar-animation-time</td>
+          <td class="value"><a href="#typenumber" class="typelink">&lt;number&gt;</a></td>
+          <td>2.0</td>
+          <td>&nbsp;</td>
+        </tr>
+      </tbody>
+    </table>
     <p>The ProgressBar control has all the properties of and pseudo-class state
       of <a href="#progressindicator">ProgressIndicator</a></p>
     <h4>Substructure</h4>
@@ -4219,6 +4295,12 @@
           <th class="value">Values</th>
           <th>Default</th>
           <th>Comments</th>
+        <tr>
+          <td class="propertyname">-fx-size</td>
+          <td class="value"><a href="#typesize" class="typelink">&lt;size&gt;</a></td>
+          <td>20</td>
+          <td>The table column header size.</td>
+        </tr>
         </tr>
       </thead>
       <tbody>
@@ -4889,7 +4971,7 @@
         </thead>
         <tbody>
           <tr>
-            <td class="propertyname">-fx-symbol-visible</td>
+            <td class="propertyname">-fx-create-symbols</td>
             <td class="value"><a href="#typeboolean" class="typelink">&lt;boolean&gt;</a></td>
             <td>true</td>
             <td>&nbsp;</td>
@@ -5148,7 +5230,6 @@
     <ul>
       <li>axis-label &mdash; Text</li>
       <li>axis-tick-mark &mdash; Path</li>
-      <li>tick-mark &mdash; Text</li>
     </ul>
     <h4><a name="valueaxis" id="valueaxis">ValueAxis</a></h4>
     <p class="styleclass">Style class: axis</p>
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/PaginationSkin.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/PaginationSkin.java	Thu Jul 12 16:27:13 2012 -0700
@@ -350,7 +350,13 @@
                     animate = false;
                 }
 
-                pagination.setCurrentPageIndex(previousIndex);
+                if (pagination.getPageFactory().call(previousIndex) != null) {
+                    pagination.setCurrentPageIndex(previousIndex);
+                } else {
+                    // Set the page index to 0 because both the current,
+                    // and the previous pages have no content.
+                    pagination.setCurrentPageIndex(0);
+                }
 
                 if (isAnimate) {
                     animate = true;
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ScrollBarSkin.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ScrollBarSkin.java	Thu Jul 12 16:27:13 2012 -0700
@@ -284,12 +284,27 @@
 
                     double delta = (getSkinnable().getOrientation() == Orientation.VERTICAL ? dy : dx);
 
-                    if (delta > 0.0 && sb.getValue() > sb.getMin()) {
-                        sb.decrement();
-                        event.consume();
-                    } else if (delta < 0.0 && sb.getValue() < sb.getMax()) {
-                        sb.increment();
-                        event.consume();
+                    /*
+                    ** RT-22941 - If this is either a touch or inertia scroll
+                    ** then we move to the position of the touch point.
+                    *
+                    * TODO: this fix causes RT-23406 ([ScrollBar, touch] Dragging scrollbar from the 
+                    * track on touchscreen causes flickering)
+                    */
+                    if (event.isDirect()) {
+                        if (trackLength > thumbLength) {
+                            getBehavior().thumbDragged(null, (getSkinnable().getOrientation() == Orientation.VERTICAL ? event.getY(): event.getX()) / trackLength);
+                            event.consume();
+                        }
+                    }
+                    else {
+                        if (delta > 0.0 && sb.getValue() > sb.getMin()) {
+                            sb.decrement();
+                            event.consume();
+                        } else if (delta < 0.0 && sb.getValue() < sb.getMax()) {
+                            sb.increment();
+                            event.consume();
+                        }
                     }
                 }
             }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ScrollPaneSkin.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ScrollPaneSkin.java	Thu Jul 12 16:27:13 2012 -0700
@@ -470,7 +470,13 @@
                 */
                 if (vsb.getVisibleAmount() < vsb.getMax()) {
                     double vRange = getSkinnable().getVmax()-getSkinnable().getVmin();
-                    double vPixelValue = vRange / getSkinnable().getHeight();
+                    double vPixelValue;
+                    if (nodeHeight > 0.0) {
+                        vPixelValue = vRange / nodeHeight;
+                    }
+                    else {
+                        vPixelValue = 0.0;
+                    }
                     double newValue = vsb.getValue()+(-event.getDeltaY())*vPixelValue;
                     if (!PlatformUtil.isEmbedded()) {
                         if ((event.getDeltaY() > 0.0 && vsb.getValue() > vsb.getMin()) ||
@@ -496,7 +502,14 @@
 
                 if (hsb.getVisibleAmount() < hsb.getMax()) {
                     double hRange = getSkinnable().getHmax()-getSkinnable().getHmin();
-                    double hPixelValue = hRange / getSkinnable().getWidth();
+                    double hPixelValue;
+                    if (nodeWidth > 0.0) {
+                        hPixelValue = hRange / nodeWidth;
+                    }
+                    else {
+                        hPixelValue = 0.0;
+                    }
+
                     double newValue = hsb.getValue()+(-event.getDeltaX())*hPixelValue;
                     if (!PlatformUtil.isEmbedded()) {
                         if ((event.getDeltaX() > 0.0 && hsb.getValue() > hsb.getMin()) ||
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TabPaneSkin.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TabPaneSkin.java	Thu Jul 12 16:27:13 2012 -0700
@@ -535,10 +535,8 @@
 
                 @Override protected void layoutChildren() {
                     if (tabsFit()) {
-                        controlButtons.showTabsMenu(false);
                         setScrollOffset(0.0);
                     } else {
-                        controlButtons.showTabsMenu(true);
                         if (!removeTab.isEmpty()) {                            
                             double offset = 0;
                             double w = tabHeaderArea.getWidth() - snapSize(controlButtons.prefWidth(-1)) - firstTabIndent() - SPACER;
@@ -811,7 +809,13 @@
             double tabBackgroundHeight = snapSize(prefHeight(-1));
             double headersPrefWidth = snapSize(headersRegion.prefWidth(-1));
             double headersPrefHeight = snapSize(headersRegion.prefHeight(-1));
-
+            
+            if (tabsFit()) {
+                controlButtons.showTabsMenu(false);
+            } else {
+                controlButtons.showTabsMenu(true);
+            }
+            
             updateHeaderClip();
 
             // RESIZE CONTROL BUTTONS
@@ -826,7 +830,7 @@
                 headerBackground.resize(snapSize(getWidth()), snapSize(getHeight()));
                 headerBackground.setVisible(true);
             }
-
+            
             double startX = 0;
             double startY = 0;
             double controlStartX = 0;
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TitledPaneSkin.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TitledPaneSkin.java	Thu Jul 12 16:27:13 2012 -0700
@@ -551,7 +551,11 @@
             int index = engine.registeredNodes.indexOf(node);
 
             if (index == -1 && direction.equals(Direction.PREVIOUS)) {
-                getSkinnable().requestFocus();
+                // If the parent is an accordion we want to focus to go outside of the
+                // accordion and to the previous focusable control.
+                if (getSkinnable().getParent() != null && getSkinnable().getParent() instanceof AccordionSkin) {
+                    new TraversalEngine(getSkinnable(), false).trav(getSkinnable().getParent(), Direction.PREVIOUS);
+                }
             }
             if (index == -1 && direction.equals(Direction.NEXT)) {
                 // If the parent is an accordion we want to focus to go outside of the
--- a/javafx-ui-controls/src/javafx/scene/chart/Axis.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/chart/Axis.java	Thu Jul 12 16:27:13 2012 -0700
@@ -743,7 +743,7 @@
                                  tick.getPosition(),getTickLabelRotation(),side);
 
                 // check if position is inside bounds
-                if(tick.getPosition() >= 0 && tick.getPosition() <= length) {
+                if(tick.getPosition() >= 0 && tick.getPosition() <= Math.ceil(length)) {
                     if (isTickLabelsVisible()) {
                         tick.textNode.setVisible((tickIndex % numLabelsToSkip) == 0);
                         tickIndex++;
@@ -767,7 +767,7 @@
                 positionTextNode(tick.textNode, getTickLabelGap() + tickMarkLength,
                                  tick.getPosition(),getTickLabelRotation(),side);
                 // check if position is inside bounds
-                if(tick.getPosition() >= 0 && tick.getPosition() <= length) {
+                if(tick.getPosition() >= 0 && tick.getPosition() <= Math.ceil(length)) {
                     if (isTickLabelsVisible()) {
                         tick.textNode.setVisible((tickIndex % numLabelsToSkip) == 0);
                         tickIndex++;
@@ -805,7 +805,7 @@
                 positionTextNode(tick.textNode, tick.getPosition(), height - tickMarkLength - getTickLabelGap(),
                         getTickLabelRotation(), side);
                 // check if position is inside bounds
-                if(tick.getPosition() >= 0 && tick.getPosition() <= length) {
+                if(tick.getPosition() >= 0 && tick.getPosition() <= Math.ceil(length)) {
                     if (isTickLabelsVisible()) {
                         tick.textNode.setVisible((tickIndex % numLabelsToSkip) == 0);
                         tickIndex++;
@@ -832,7 +832,7 @@
                 positionTextNode(tick.textNode,xPos, tickMarkLength + getTickLabelGap(),
                                 getTickLabelRotation(),side);
                 // check if position is inside bounds
-                if(xPos >= 0 && xPos <= length) {
+                if(xPos >= 0 && xPos <= Math.ceil(length)) {
                     if (isTickLabelsVisible()) {
                         tick.textNode.setVisible((tickIndex % numLabelsToSkip) == 0);
                         tickIndex++;
--- a/javafx-ui-controls/src/javafx/scene/control/Control.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/src/javafx/scene/control/Control.java	Thu Jul 12 16:27:13 2012 -0700
@@ -1096,7 +1096,7 @@
     @Deprecated
     @Override public void impl_processCSS(boolean reapply) {
         if (reapply && getUserAgentStylesheet() != null) {
-            StyleManager.getInstance().addUserAgentStylesheet(getUserAgentStylesheet());
+            StyleManager.getInstance().addUserAgentStylesheet(getScene(), getUserAgentStylesheet());
         }
 
         super.impl_processCSS(reapply);
--- a/javafx-ui-controls/test/javafx/scene/control/ButtonTest.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/test/javafx/scene/control/ButtonTest.java	Thu Jul 12 16:27:13 2012 -0700
@@ -5,7 +5,9 @@
 package javafx.scene.control;
 
 import com.sun.javafx.pgstub.StubToolkit;
+import com.sun.javafx.scene.layout.region.BackgroundFill;
 import com.sun.javafx.tk.Toolkit;
+import java.util.List;
 import static javafx.scene.control.ControlTestUtils.*;
 import static org.junit.Assert.*;
 
@@ -19,7 +21,12 @@
 import javafx.scene.control.ContextMenu;
 import javafx.scene.input.KeyCode;
 import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
 import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.LinearGradient;
+import javafx.scene.paint.Stop;
 import javafx.scene.shape.Rectangle;
 import javafx.stage.Stage;
 import javafx.stage.WindowEvent;
@@ -341,6 +348,85 @@
         tk.firePulse();                      
     }
 
+    static class MyButton extends Button {
+        MyButton(String text) {
+            super(text);
+        }
+        
+        void setHoverPseudoclassState(boolean b) {
+            setHover(b);
+        }
+    }    
+    
+    List<Stop> getStops(Button button) {
+        Skin skin = button.getSkin();
+        Region region = (Region)skin.getNode();
+        List<BackgroundFill> fills = region.impl_getBackgroundFills();
+        BackgroundFill top = fills.get(fills.size()-1);
+        LinearGradient topFill = (LinearGradient)top.getFill();
+        return topFill.getStops();        
+    }
+
+    @Test
+    public void testRT_23207() {
+        
+        HBox hBox = new HBox();
+        hBox.setSpacing(5);
+        hBox.setTranslateY(30);
+        MyButton red = new MyButton("Red");
+        red.setStyle("-fx-base: red;");
+        MyButton green = new MyButton("Green");
+        green.setStyle("-fx-base: green;");
+        hBox.getChildren().add(red);
+        hBox.getChildren().add(green);
+                
+        Scene scene = new Scene(hBox, 500, 300);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        
+        Toolkit.getToolkit().firePulse();
+        
+        List<Stop> redStops0 = getStops(red);
+        List<Stop> greenStops0 = getStops(green);
+        
+        red.setHoverPseudoclassState(true);
+        
+        Toolkit.getToolkit().firePulse();
+
+        List<Stop> redStops1 = getStops(red);
+        List<Stop> greenStops1 = getStops(green);
+                
+        red.setHoverPseudoclassState(false);
+        green.setHoverPseudoclassState(true);
+        
+        Toolkit.getToolkit().firePulse();
+        
+        List<Stop> redStops2 = getStops(red);
+        List<Stop> greenStops2 = getStops(green);
+
+        green.setHoverPseudoclassState(false);
+        
+        Toolkit.getToolkit().firePulse();
+
+        List<Stop> redStops3 = getStops(red);
+        List<Stop> greenStops3 = getStops(green);
+        
+        // did red change color after red hover=true?
+        assertFalse(redStops0.equals(redStops1));
+        // did red change back to original color after green hover=true?
+        assertTrue(redStops0.equals(redStops2));
+        // did red stay original color after green hover=false?
+        assertTrue(redStops0.equals(redStops3));
+        // did green stay green after red hover=true?
+        assertTrue(greenStops0.equals(greenStops1));
+        // did green change after green hover=true?
+        assertFalse(greenStops0.equals(greenStops2));
+        // did green revert to original after green hover=false?
+        // This is the acid test. If this fails, then RT-23207 is present.
+        assertTrue(greenStops0.equals(greenStops3));
+        
+    }    
 
     
 //  private Button button1;
--- a/javafx-ui-controls/test/javafx/scene/control/TabPaneTest.java	Wed Jul 11 12:24:20 2012 -0700
+++ b/javafx-ui-controls/test/javafx/scene/control/TabPaneTest.java	Thu Jul 12 16:27:13 2012 -0700
@@ -9,6 +9,7 @@
 import com.sun.javafx.pgstub.StubToolkit;
 import com.sun.javafx.scene.control.skin.TabPaneSkin;
 import com.sun.javafx.tk.Toolkit;
+import javafx.application.Platform;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.DoubleProperty;
 import javafx.beans.property.ObjectProperty;
@@ -20,9 +21,12 @@
 import javafx.event.Event;
 import javafx.event.EventHandler;
 import javafx.geometry.Side;
+import javafx.scene.Group;
 import javafx.scene.Scene;
+import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
 import javafx.stage.Stage;
 import static org.junit.Assert.*;
 
@@ -767,4 +771,50 @@
         assertEquals(0, tabPane.getSelectionModel().getSelectedIndex());
         assertEquals(tab2, tabPane.getSelectionModel().getSelectedItem());        
     }    
+
+
+    boolean button1Focused = false;
+    @Test public void focusTraversalShouldLookInsideEmbeddedEngines() {
+
+        Button b1 = new Button("Button1");
+        final ChangeListener<Boolean> focusListener = new ChangeListener<Boolean>() {
+            @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldVal, Boolean newVal) {
+                button1Focused = true;
+            }
+        };
+        b1.focusedProperty().addListener(focusListener);
+
+        final ScrollPane sp = new ScrollPane();
+        final VBox vbox1 = new VBox();
+        vbox1.setSpacing(10);
+        vbox1.setTranslateX(10);
+        vbox1.setTranslateY(10);
+        vbox1.getChildren().addAll(b1);
+        tab1.setContent(vbox1);
+        sp.setContent(vbox1);
+        tab1.setContent(sp);
+        tabPane.getTabs().add(tab1);
+
+        tabPane.getTabs().add(tab2);
+
+        final Scene scene1 = new Scene(new Group(), 400, 400);
+        ((Group)scene1.getRoot()).getChildren().add(tabPane);
+        
+        stage.setScene(scene1);
+        stage.show();
+
+        final KeyEvent tabEvent = KeyEvent.impl_keyEvent(null, "", "", 0x09,
+                                                         false, false, false, false,
+                                                         KeyEvent.KEY_PRESSED);
+        Platform.runLater(new Runnable() {
+            @Override public void run() {
+                tabPane.requestFocus();
+                Event.fireEvent(tabPane, tabEvent);
+
+            }
+        });
+
+        assertTrue(button1Focused);
+
+    }    
 }