changeset 4150:79c040d01c80 8.0-b97

Merge
author ngthomas
date Wed, 03 Jul 2013 11:33:48 -0700
parents fa1eb6d3e875 bc913850bda0
children 7e8af993c478 409498e0a997
files
diffstat 18 files changed, 273 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- a/build.gradle	Tue Jul 02 23:11:35 2013 -0700
+++ b/build.gradle	Wed Jul 03 11:33:48 2013 -0700
@@ -1166,10 +1166,6 @@
 
     test {
         jvmArgs "-Djavafx.toolkit=com.sun.javafx.pgstub.StubToolkit"
-        // TODO fix the Controls tests so that we can run them all in one VM
-        // This is highly unfortunate, test execution time goes from 7 sec to 2 min 8 sec
-        // however there are 8 failing tests when we don't fork. Need to fix those tests.
-        forkEvery = 1
     }
 
     // TODO Css2Bin really should be moved out and put into buildSrc if it can be
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ComboBoxBaseSkin.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ComboBoxBaseSkin.java	Wed Jul 03 11:33:48 2013 -0700
@@ -132,6 +132,13 @@
         displayNode = getDisplayNode();
         if (displayNode != null && !children.contains(displayNode)) {
             children.add(displayNode);
+
+            // RT-20575: The display node is being brought into the scenegraph
+            // early so we get the correct prefHeight, but at this point it
+            // may not have had a layout pass run over it itself, so the
+            // displayNode will return a prefHeight of 0. Here we are forcing
+            // a one-off run of the layout over the displayNode.
+            displayNode.impl_processCSS(true);
         }
     }
     
@@ -181,13 +188,6 @@
     @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         if (displayNode == null) {
             updateDisplayArea();
-            
-            // RT-20575: The display node is being brought into the scenegraph
-            // early so we get the correct prefHeight, but at this point it
-            // may not have had a layout pass run over it itself, so the 
-            // displayNode will return a prefHeight of 0. Here we are forcing
-            // a one-off run of the layout over the displayNode.
-            displayNode.impl_processCSS(true);
         }
 
         double ph;
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/NestedTableColumnHeader.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/NestedTableColumnHeader.java	Wed Jul 03 11:33:48 2013 -0700
@@ -74,13 +74,6 @@
         if (getTableColumn() != null) {
             changeListenerHandler.registerChangeListener(getTableColumn().textProperty(), "TABLE_COLUMN_TEXT");
         }
-        
-        // watching for changes to the view columns in either table or tableColumn.
-        if (getTableColumn() == null && getTableViewSkin() != null) {
-            setColumns(getTableViewSkin().getColumns());
-        } else if (getTableColumn() != null) {
-            setColumns(getTableColumn().getColumns());
-        }
 
         changeListenerHandler.registerChangeListener(skin.columnResizePolicyProperty(), "TABLE_VIEW_COLUMN_RESIZE_POLICY");
     }
@@ -148,11 +141,18 @@
         if (this.columns != null) {
             this.columns.addListener(weakColumnsListener);
         }
-
-        updateTableColumnHeaders();
     }
     
     void updateTableColumnHeaders() {
+        // watching for changes to the view columns in either table or tableColumn.
+        if (getTableColumn() == null && getTableViewSkin() != null) {
+            setColumns(getTableViewSkin().getColumns());
+        } else if (getTableColumn() != null) {
+            setColumns(getTableColumn().getColumns());
+        }
+
+        // update the column headers...
+
         // iterate through all current headers, telling them to clean up
         for (int i = 0; i < getColumnHeaders().size(); i++) {
             TableColumnHeader header = getColumnHeaders().get(i);
@@ -398,7 +398,11 @@
     /* END OF COLUMN RESIZING   */
     /* **************************/
 
+    boolean updateColumns = true;
+
     void setHeadersNeedUpdate() {
+        updateColumns = true;
+
         // go through children columns - they should update too
         for (int i = 0; i < getColumnHeaders().size(); i++) {
             TableColumnHeader header = getColumnHeaders().get(i);
@@ -406,9 +410,16 @@
                 ((NestedTableColumnHeader)header).setHeadersNeedUpdate();
             }
         }
-        updateTableColumnHeaders();
         requestLayout();
     }
+
+    private void checkState() {
+        if (updateColumns) {
+            updateTableColumnHeaders();
+            updateColumns = false;
+            getParent().requestLayout();
+        }
+    }
     
     @Override protected void layoutChildren() {
 
@@ -459,6 +470,8 @@
 
     // sum up all children columns
     @Override protected double computePrefWidth(double height) {
+        checkState();
+
         double width = 0.0F;
 
         if (getColumns() != null) {
@@ -473,6 +486,8 @@
     }
 
     @Override protected double computePrefHeight(double width) {
+        checkState();
+
         double height = 0.0F;
 
         if (getColumnHeaders() != null) {
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeTableViewSkin.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeTableViewSkin.java	Wed Jul 03 11:33:48 2013 -0700
@@ -145,7 +145,7 @@
                  getRoot().setExpanded(true);
             }
             // update the item count in the flow and behavior instances
-            rowCountDirty = true;
+            updateRowCount();
         } else if ("ROW_FACTORY".equals(p)) {
             flow.recreateCells();
         } else if ("TREE_ITEM_COUNT".equals(p)) {
--- a/modules/controls/src/main/java/javafx/scene/control/ComboBoxBase.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/ComboBoxBase.java	Wed Jul 03 11:33:48 2013 -0700
@@ -216,7 +216,9 @@
      * The {@code ComboBox} prompt text to display, or <tt>null</tt> if no 
      * prompt text is displayed. Prompt text is not displayed in all circumstances,
      * it is dependent upon the subclasses of ComboBoxBase to clarify when
-     * promptText will be shown.
+     * promptText will be shown. For example, in most cases prompt text will never be
+     * shown when a combo box is non-editable (that is, prompt text is only shown
+     * when user input is allowed via text input).
      */
     private StringProperty promptText = new SimpleStringProperty(this, "promptText", "") {
         @Override protected void invalidated() {
--- a/modules/controls/src/main/java/javafx/scene/control/TextInputControl.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/TextInputControl.java	Wed Jul 03 11:33:48 2013 -0700
@@ -291,7 +291,7 @@
      */
     private BooleanProperty editable = new SimpleBooleanProperty(this, "editable", true) {
         @Override protected void invalidated() {
-            pseudoClassStateChanged(PSEUDO_CLASS_READONLY, get());
+            pseudoClassStateChanged(PSEUDO_CLASS_READONLY, ! get());
         }
     };
     public final boolean isEditable() { return editable.getValue(); }
--- a/modules/controls/src/main/java/javafx/scene/control/TreeTableCell.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/TreeTableCell.java	Wed Jul 03 11:33:48 2013 -0700
@@ -222,23 +222,24 @@
                             oldTableView.rootProperty().removeListener(weakRootPropertyListener);
                         }
                     }
-                    
-                    if (get() != null) {
-                        sm = get().getSelectionModel();
+
+                    TreeTableView newTreeTableView = get();
+                    if (newTreeTableView != null) {
+                        sm = newTreeTableView.getSelectionModel();
                         if (sm != null) {
                             sm.getSelectedCells().addListener(weakSelectedListener);
                         }
 
-                        fm = get().getFocusModel();
+                        fm = newTreeTableView.getFocusModel();
                         if (fm != null) {
                             fm.focusedCellProperty().addListener(weakFocusedListener);
                         }
 
-                        get().editingCellProperty().addListener(weakEditingListener);
-                        get().getVisibleLeafColumns().addListener(weakVisibleLeafColumnsListener);
-                        get().rootProperty().addListener(weakRootPropertyListener);
+                        newTreeTableView.editingCellProperty().addListener(weakEditingListener);
+                        newTreeTableView.getVisibleLeafColumns().addListener(weakVisibleLeafColumnsListener);
+                        newTreeTableView.rootProperty().addListener(weakRootPropertyListener);
                         
-                        weakTableViewRef = new WeakReference<TreeTableView<S>>(get());
+                        weakTableViewRef = new WeakReference<TreeTableView<S>>(newTreeTableView);
                     }
                     
                     updateColumnIndex();
--- a/modules/controls/src/main/java/javafx/scene/control/cell/PropertyValueFactory.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/cell/PropertyValueFactory.java	Wed Jul 03 11:33:48 2013 -0700
@@ -140,16 +140,13 @@
                 this.propertyRef = new PropertyReference<T>(rowData.getClass(), getProperty());
             }
 
-            return propertyRef.getProperty(rowData);
-        } catch (IllegalStateException e) {
-            try {
-                // attempt to just get the value
+            if (propertyRef.hasProperty()) {
+                return propertyRef.getProperty(rowData);
+            } else {
                 T value = propertyRef.get(rowData);
                 return new ReadOnlyObjectWrapper<T>(value);
-            } catch (IllegalStateException e2) {
-                // fall through to logged exception below
             }
-
+        } catch (IllegalStateException e) {
             // log the warning and move on
             final PlatformLogger logger = Logging.getControlsLogger();
             if (logger.isLoggable(Level.WARNING)) {
--- a/modules/controls/src/test/java/javafx/scene/chart/StackedAreaChartTest.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/chart/StackedAreaChartTest.java	Wed Jul 03 11:33:48 2013 -0700
@@ -41,7 +41,7 @@
 
 import org.junit.Ignore;
 
-
+@Ignore
 public class StackedAreaChartTest extends XYChartTestBase {
     
     private Scene scene;
--- a/modules/controls/src/test/java/javafx/scene/chart/StackedBarChartTest.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/chart/StackedBarChartTest.java	Wed Jul 03 11:33:48 2013 -0700
@@ -42,6 +42,7 @@
 
 import org.junit.Ignore;
 
+@Ignore
 public class StackedBarChartTest extends XYChartTestBase {
     
     private Scene scene;
--- a/modules/controls/src/test/java/javafx/scene/control/TextFieldTest.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TextFieldTest.java	Wed Jul 03 11:33:48 2013 -0700
@@ -25,10 +25,13 @@
 
 package javafx.scene.control;
 
+import com.sun.javafx.scene.control.infrastructure.StageLoader;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.property.SimpleStringProperty;
 import javafx.beans.property.StringProperty;
+import javafx.collections.ObservableSet;
+import javafx.css.PseudoClass;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
 import javafx.scene.Scene;
@@ -39,10 +42,6 @@
 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.*;
 import static org.junit.Assert.*;
 
-/**
- *
- * @author srikalyc
- */
 public class TextFieldTest {
     private TextField txtField;//Empty string
     private TextField dummyTxtField;//With string value
@@ -141,6 +140,34 @@
         assertEquals(100, txtField.getPrefColumnCount(), 0);
     }
 
+    @Test public void pseudoClassState_isReadOnly() {
+        new StageLoader(txtField);
+        txtField.impl_processCSS(true);
+
+        txtField.setEditable(false);
+        ObservableSet<PseudoClass> pcSet = txtField.getPseudoClassStates();
+        boolean match = false;
+        for (PseudoClass pc : pcSet) {
+            if (match) break;
+            match = "readonly".equals(pc.getPseudoClassName());
+        }
+        assertTrue(match);
+    }
+
+    @Test public void pseudoClassState_isNotReadOnly() {
+        new StageLoader(txtField);
+        txtField.impl_processCSS(true);
+
+        txtField.setEditable(true);
+        ObservableSet<PseudoClass> pcSet = txtField.getPseudoClassStates();
+        boolean match = false;
+        for (PseudoClass pc : pcSet) {
+            if (match) break;
+            match = "readonly".equals(pc.getPseudoClassName());
+        }
+        assertFalse(match);
+    }
+
     /*********************************************************************
      * Tests for property binding                                        *
      ********************************************************************/
--- a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java	Wed Jul 03 11:33:48 2013 -0700
@@ -2094,4 +2094,23 @@
         assertEquals(child1, treeTableView.getEditingItem());
         assertTrue(cell.isEditing());
     }
+
+    @Test public void test_rt31404() {
+        installChildren();
+
+        TreeTableColumn<String,String> firstNameCol = new TreeTableColumn<>("First Name");
+        firstNameCol.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, String>, ObservableValue<String>>() {
+            @Override public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<String, String> param) {
+                return new ReadOnlyStringWrapper(param.getValue().getValue());
+            }
+        });
+
+        treeTableView.getColumns().add(firstNameCol);
+
+        IndexedCell cell = VirtualFlowTestUtils.getCell(treeTableView, 0, 0);
+        assertEquals("Root", cell.getText());
+
+        treeTableView.setShowRoot(false);
+        assertEquals("Child 1", cell.getText());
+    }
 }
--- a/modules/controls/src/test/java/javafx/scene/control/TreeViewTest.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeViewTest.java	Wed Jul 03 11:33:48 2013 -0700
@@ -1047,4 +1047,14 @@
         assertEquals(child1, treeView.getEditingItem());
         assertTrue(cell.isEditing());
     }
+
+    @Test public void test_rt31404() {
+        installChildren();
+
+        IndexedCell cell = VirtualFlowTestUtils.getCell(treeView, 0);
+        assertEquals("Root", cell.getText());
+
+        treeView.setShowRoot(false);
+        assertEquals("Child 1", cell.getText());
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/css/ParsedValueImpl.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/css/ParsedValueImpl.java	Wed Jul 03 11:33:48 2013 -0700
@@ -30,8 +30,6 @@
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import javafx.css.ParsedValue;
 import javafx.css.StyleConverter;
 import javafx.scene.paint.Color;
@@ -244,17 +242,6 @@
         return (T)((converter != null) ? converter.convert(this, font) : value);
     }
 
-    private final static String newline;
-    static {
-        newline = AccessController.doPrivileged(
-            new PrivilegedAction<String>() {
-            @Override
-                public String run() {
-                    return System.getProperty("line.separator");
-            }
-        });
-    }
-
     private static int indent = 0;
 
     private static String spaces() {
@@ -270,6 +257,7 @@
     }
 
     @Override public String toString() {
+        final String newline = System.lineSeparator();
         StringBuilder sbuf = new StringBuilder();
         sbuf.append(spaces())
             .append((lookup? "<Value lookup=\"true\">" : "<Value>"))
@@ -294,6 +282,7 @@
     }
 
     private void appendValue(StringBuilder sbuf, Object value, String tag) {
+        final String newline = System.lineSeparator();
         if (value instanceof ParsedValueImpl[][]) {
             ParsedValueImpl[][] layers = (ParsedValueImpl[][])value;
             sbuf.append(spaces())
--- a/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java	Wed Jul 03 11:33:48 2013 -0700
@@ -1193,17 +1193,7 @@
             container.clearCache();
         }
 
-        final Iterator<Window> windows =
-                AccessController.doPrivileged(
-                        new PrivilegedAction<Iterator<Window>>() {
-                            @Override
-                            public Iterator<Window> run() {
-                                return Window.impl_getWindows();
-                            }
-                        });
-        while (windows.hasNext()) {
-            final Window window = windows.next();
-            final Scene scene = window.getScene();
+        for (Scene scene : cacheContainerMap.keySet()) {
             if (scene == null) {
                 continue;
             }
--- a/modules/graphics/src/main/java/javafx/scene/CssStyleHelper.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/graphics/src/main/java/javafx/scene/CssStyleHelper.java	Wed Jul 03 11:33:48 2013 -0700
@@ -30,6 +30,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -984,6 +985,17 @@
             ObjectProperty<StyleOrigin> whence,
             List<Style> styleList) {
 
+        return resolveLookups(styleable, parsedValue, states, whence, null, styleList);
+    }
+
+    // to resolve a lookup, we just need to find the parsed value.
+    private ParsedValueImpl resolveLookups(
+            Styleable styleable,
+            ParsedValueImpl parsedValue,
+            Set<PseudoClass> states,
+            ObjectProperty<StyleOrigin> whence,
+            Set<CascadingStyle> resolves, List<Style> styleList) {
+
 
         //
         // either the value itself is a lookup, or the value contain a lookup
@@ -1002,6 +1014,25 @@
 
                 if (resolved != null) {
 
+                    if (resolves != null) {
+
+                        if (resolves.contains(resolved) == false) {
+                            resolves.add(resolved);
+
+                        } else {
+
+                            if (LOGGER.isLoggable(Level.WARNING)) {
+                                LOGGER.warning("Loop detected while resolving: '" + sval + "'");
+                            }
+                            throw new IllegalArgumentException(resolved.getRule().toString());
+
+                        }
+
+                    } else {
+                        resolves = new HashSet<>();
+                        resolves.add(resolved);
+                    }
+
                     if (styleList != null) {
                         final Style style = resolved.getStyle();
                         if (style != null && !styleList.contains(style)) {
@@ -1024,7 +1055,7 @@
                     // the resolved value may itself need to be resolved.
                     // For example, if the value "color" resolves to "base",
                     // then "base" will need to be resolved as well.
-                    return resolveLookups(styleable, resolved.getParsedValueImpl(), states, whence, styleList);
+                    return resolveLookups(styleable, resolved.getParsedValueImpl(), states, whence, resolves, styleList);
                 }
             }
         }
@@ -1042,7 +1073,7 @@
                 for (int ll=0; ll<layers[l].length; ll++) {
                     if (layers[l][ll] == null) continue;
                     layers[l][ll].setResolved(
-                        resolveLookups(styleable, layers[l][ll], states, whence, styleList)
+                        resolveLookups(styleable, layers[l][ll], states, whence, null, styleList)
                     );
                 }
             }
@@ -1053,7 +1084,7 @@
             for (int l=0; l<layer.length; l++) {
                 if (layer[l] == null) continue;
                 layer[l].setResolved(
-                    resolveLookups(styleable, layer[l], states, whence, styleList)
+                    resolveLookups(styleable, layer[l], states, whence, null, styleList)
                 );
             }
         }
@@ -1160,11 +1191,11 @@
         final ParsedValueImpl cssValue = style.getParsedValueImpl();
         if (cssValue != null && !("null").equals(cssValue.getValue())) {
 
-            ObjectProperty<StyleOrigin> whence = new SimpleObjectProperty<StyleOrigin>(style.getOrigin());
-            final ParsedValueImpl resolved =
-                resolveLookups(node, cssValue, states, whence, styleList);
+            ParsedValueImpl resolved = null;
+            try {
 
-            try {
+                ObjectProperty<StyleOrigin> whence = new SimpleObjectProperty<StyleOrigin>(style.getOrigin());
+                resolved = resolveLookups(node, cssValue, states, whence, styleList);
 
                 final String property = cssMetaData.getProperty();
 
@@ -1285,7 +1316,7 @@
                 }
                 return SKIP;
             } finally {
-                resolved.setResolved(null);
+                if (resolved != null) resolved.setResolved(null);
             }
 
         }
--- a/modules/graphics/src/main/java/javafx/scene/Node.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/graphics/src/main/java/javafx/scene/Node.java	Wed Jul 03 11:33:48 2013 -0700
@@ -8560,7 +8560,6 @@
     @Deprecated // SB-dependency: RT-21206 has been filed to track this
     public final void impl_processCSS(boolean reapply) {
 
-        assert(getScene() != null);
         if (getScene() == null) return;
 
         //
--- a/modules/graphics/src/stub/java/com/sun/javafx/css/StylesheetTest.java	Tue Jul 02 23:11:35 2013 -0700
+++ b/modules/graphics/src/stub/java/com/sun/javafx/css/StylesheetTest.java	Wed Jul 03 11:33:48 2013 -0700
@@ -29,8 +29,14 @@
 import java.net.URL;
 import java.util.Collections;
 import java.util.List;
+import javafx.css.StyleableProperty;
 import javafx.scene.Group;
 import javafx.scene.Scene;
+import javafx.scene.layout.StackPane;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.LinearGradient;
+import javafx.scene.paint.Paint;
+import javafx.scene.paint.RadialGradient;
 import javafx.scene.shape.Rectangle;
 import javafx.stage.Stage;
 import org.junit.*;
@@ -215,9 +221,122 @@
         } catch (Exception e) {
             // Something other than an NPE should still raise a red flag,
             // but the exception is not what RT-23140 fixed.
+
             fail("Exception not expected: " + e.toString());
         }
         
     }
+
+    @Test public void testRT_31316() {
+
+        try {
+
+            Rectangle rect = new Rectangle(50,50);
+            rect.setStyle("-fx-base: red; -fx-fill: -fx-base;");
+            rect.setFill(Color.GREEN);
+
+            Group root = new Group();
+            root.getChildren().add(rect);
+            Scene scene = new Scene(root, 500, 500);
+
+            root.impl_processCSS(true);
+
+            // Shows inline style works.
+            assertEquals(Color.RED, rect.getFill());
+
+            // reset fill
+            ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null);
+
+            // loop in style!
+            rect.setStyle("-fx-base: -fx-fill; -fx-fill: -fx-base;");
+            root.impl_processCSS(true);
+
+            // Shows value was left alone
+            assertNull(rect.getFill());
+
+
+        } catch (Exception e) {
+            // The code generates an IllegalArgumentException that should never reach here
+            fail("Exception not expected: " + e.toString());
+        }
+
+    }
+
+    @Test public void testRT_31316_with_complex_value() {
+
+        try {
+
+            Rectangle rect = new Rectangle(50,50);
+            rect.setStyle("-fx-base: red; -fx-color: -fx-base; -fx-fill: radial-gradient(radius 100%, red, -fx-color);");
+            rect.setFill(Color.GREEN);
+
+            Group root = new Group();
+            root.getChildren().add(rect);
+            Scene scene = new Scene(root, 500, 500);
+
+            root.impl_processCSS(true);
+
+            // Shows inline style works.
+            assertTrue(rect.getFill() instanceof RadialGradient);
+
+            // reset fill
+            ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null);
+
+            // loop in style!
+            rect.setStyle("-fx-base: -fx-color; -fx-color: -fx-base; -fx-fill: radial-gradient(radius 100%, red, -fx-color);");
+
+            root.impl_processCSS(true);
+
+            // Shows value was left alone
+            assertNull(rect.getFill());
+
+        } catch (Exception e) {
+            // The code generates an IllegalArgumentException that should never reach here
+            fail("Exception not expected: " + e.toString());
+        }
+    }
+
+
+    @Test public void testRT_31316_with_complex_scenegraph() {
+
+        try {
+
+            Rectangle rect = new Rectangle(50,50);
+            rect.setStyle("-fx-fill: radial-gradient(radius 100%, red, -fx-color);");
+            rect.setFill(Color.GREEN);
+
+            StackPane pane = new StackPane();
+            pane.setStyle("-fx-color: -fx-base;");
+            pane.getChildren().add(rect);
+
+            Group root = new Group();
+            // loop in style!
+            root.setStyle("-fx-base: red;");
+            root.getChildren().add(pane);
+            Scene scene = new Scene(root, 500, 500);
+
+            root.impl_processCSS(true);
+
+            // Shows inline style works.
+            assertTrue(rect.getFill() instanceof RadialGradient);
+
+            // reset fill
+            ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null);
+
+            // loop in style
+            root.setStyle("-fx-base: -fx-color;");
+
+            root.impl_processCSS(true);
+
+            // Shows value was left alone
+            assertNull(rect.getFill());
+
+        } catch (Exception e) {
+            // The code generates an IllegalArgumentException that should never reach here
+            fail("Exception not expected: " + e.toString());
+        }
+
+    }
+
     
 }