changeset 9618:33e0a9be1383 jdk-9+110

Merge
author kcr
date Thu, 10 Mar 2016 14:16:20 -0800
parents 342b190cf11f 3643238f1833
children 2209ba2006b3 42b461505f27 03bc046de627
files modules/graphics/src/test/java/netscape/javascript/JSObjectTest.java
diffstat 45 files changed, 635 insertions(+), 713 deletions(-) [+]
line wrap: on
line diff
--- a/build.gradle	Thu Mar 10 01:24:59 2016 -0800
+++ b/build.gradle	Thu Mar 10 14:16:20 2016 -0800
@@ -1256,7 +1256,6 @@
     // Java 7 but when we switch to 8 this will be needed, and probably again when
     // we start building with Java 9.
     test {
-        jvmArgs("-Djava.ext.dirs=");
         executable = JAVA;
         enableAssertions = true;
         testLogging.exceptionFormat = "full";
@@ -1533,7 +1532,6 @@
                 classpath += files("$buildDir/classes/main")
                 classpath += files("$buildDir/classes/jsl-compilers/decora")
                 args = ["-i", sourceDir, "-o", destinationDir, "-t", "-pkg", "com/sun/scenario/effect", "$settings.outputs", "$settings.fileName"]
-                jvmArgs "-Djava.ext.dirs="
             }
         }
     }
@@ -1624,7 +1622,6 @@
                 classpath = configurations.compile + configurations.antlr3
                 classpath += files("$buildDir/classes/jsl-compilers/prism", "modules/graphics/src/main/jsl-prism") // for the .stg
                 args = ["-i", sourceDir, "-o", destinationDir, "-t", "-pkg", "com/sun/prism", "-d3d", "-es2", "-name", "$file"]
-                jvmArgs "-Djava.ext.dirs="
             }
         }
     }
@@ -1639,7 +1636,7 @@
 
     test {
         def cssDir = file("$buildDir/classes/main/javafx")
-        jvmArgs "-Djava.ext.dirs=", "-Djavafx.toolkit=test.com.sun.javafx.pgstub.StubToolkit",
+        jvmArgs "-Djavafx.toolkit=test.com.sun.javafx.pgstub.StubToolkit",
             "-DCSS_META_DATA_TEST_DIR=$cssDir"
         enableAssertions = true
         testLogging.exceptionFormat = "full"
@@ -1722,7 +1719,6 @@
                         project(":base").sourceSets.main.output)
                 main = "com.sun.javafx.css.parser.Css2Bin"
                 args css
-                jvmArgs "-Djava.ext.dirs="
             }
         }
     }
@@ -2255,7 +2251,7 @@
                                      "com.sun.media.jfxmediaimpl.platform.osx.OSXMediaPlayer"] );
             }
             exec {
-                commandLine ("${JAVAH}", "-J-Djava.ext.dirs=", "-d", "${generatedHeadersDir}", "-classpath", "${classpath.asPath}");
+                commandLine ("${JAVAH}", "-d", "${generatedHeadersDir}", "-classpath", "${classpath.asPath}");
                 args classesList;
             }
         }
@@ -2272,7 +2268,7 @@
             mkdir generatedHeadersDir;
 
             exec {
-                commandLine("$JAVA", "-Djava.ext.dirs=", "-classpath", "${classpath.asPath}");
+                commandLine("$JAVA", "-classpath", "${classpath.asPath}");
                 args("headergen.HeaderGen", "$headerpath", "$srcRoot");
             }
         }
@@ -2532,7 +2528,7 @@
             def dest = file("$buildDir/generated-src/headers");
             mkdir dest;
             exec {
-                commandLine("$JAVAH", "-J-Djava.ext.dirs=", "-d", "$dest",
+                commandLine("$JAVAH", "-d", "$dest",
                             "-classpath", "${classpath.asPath}");
                 args("java.lang.Character",
                      "java.net.IDN",
@@ -2787,7 +2783,7 @@
         compile.options.fork = true
         compile.options.forkOptions.executable = JAVAC
         compile.options.warnings = IS_LINT
-        compile.options.compilerArgs = ["-Djava.ext.dirs=", "-XDignore.symbol.file", "-encoding", "UTF-8"]
+        compile.options.compilerArgs = ["-XDignore.symbol.file", "-encoding", "UTF-8"]
         if (!DO_BUILD_SDK_FOR_TEST) {
             compile.classpath = files(jfxrtJarFromSdk) + compile.classpath
         }
@@ -2844,11 +2840,18 @@
     executable = JAVADOC
     def projectsToDocument = [
             project(":base"), project(":graphics"), project(":controls"), project(":media"),
-            project(":swing"), project(":swt"), project(":fxml"), project(":web")]
+            project(":swing"), /*project(":swt"),*/ project(":fxml"), project(":web")]
     source(projectsToDocument.collect({
         [it.sourceSets.main.java]
     }));
     setDestinationDir(new File(buildDir, 'javadoc'));
+    // FIXME: The following is a workaround for JDK-8151191; it should be
+    // reverted once that bug is fixed
+    classpath = rootProject.BUILD_SRC
+    classpath += files(projectsToDocument.collect { project ->
+        project.sourceSets.main.java.srcDirs
+    });
+    /*
     // Might need a classpath
     classpath = files(projectsToDocument.collect { project ->
         project.sourceSets.main.compileClasspath
@@ -2856,6 +2859,7 @@
     classpath += files(projectsToDocument.collect { project ->
         project.sourceSets.main.output
     });
+    */
     exclude("com/**/*", "Compile*", "javafx/builder/**/*", "javafx/scene/accessibility/**/*");
     options.windowTitle("${javadocTitle}")
     options.header("${javadocHeader}")
--- a/buildSrc/build.gradle	Thu Mar 10 01:24:59 2016 -0800
+++ b/buildSrc/build.gradle	Thu Mar 10 14:16:20 2016 -0800
@@ -95,7 +95,6 @@
 // Java 7 but when we switch to 8 this will be needed, and probably again when
 // we start building with Java 9.
 test {
-    jvmArgs("-Djava.ext.dirs=");
     enableAssertions = true;
     testLogging.exceptionFormat = "full";
     scanForTestClasses = false;
--- a/buildSrc/src/main/groovy/com/sun/javafx/gradle/JavaHeaderTask.groovy	Thu Mar 10 01:24:59 2016 -0800
+++ b/buildSrc/src/main/groovy/com/sun/javafx/gradle/JavaHeaderTask.groovy	Thu Mar 10 14:16:20 2016 -0800
@@ -89,7 +89,7 @@
         }
         // Execute javah
         project.exec({
-            commandLine("$project.JAVAH", "-J-Djava.ext.dirs=", "-d", "$output", "-classpath", "${classpath.asPath}");
+            commandLine("$project.JAVAH", "-d", "$output", "-classpath", "${classpath.asPath}");
             args(classNames);
         });
     }
--- a/modules/controls/src/main/java/javafx/scene/control/ListCell.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/ListCell.java	Thu Mar 10 14:16:20 2016 -0800
@@ -29,6 +29,7 @@
 import java.util.List;
 
 import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
 import javafx.beans.WeakInvalidationListener;
 import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.beans.property.ReadOnlyObjectWrapper;
@@ -172,15 +173,21 @@
      * Listens to the items property on the ListView. Whenever the entire list is changed,
      * we have to unhook the weakItemsListener and update the item.
      */
-    private final ChangeListener<ObservableList<T>> itemsPropertyListener = new ChangeListener<ObservableList<T>>() {
-        @Override public void changed(ObservableValue<? extends ObservableList<T>> observable,
-                                      ObservableList<T> oldValue,
-                                      ObservableList<T> newValue) {
-            if (oldValue != null) {
-                oldValue.removeListener(weakItemsListener);
+    private final InvalidationListener itemsPropertyListener = new InvalidationListener() {
+        private WeakReference<ObservableList<T>> weakItemsRef = new WeakReference<>(null);
+
+        @Override public void invalidated(Observable observable) {
+            ObservableList<T> oldItems = weakItemsRef.get();
+            if (oldItems != null) {
+                oldItems.removeListener(weakItemsListener);
             }
-            if (newValue != null) {
-                newValue.addListener(weakItemsListener);
+
+            ListView<T> listView = getListView();
+            ObservableList<T> items = listView == null ? null : listView.getItems();
+            weakItemsRef = new WeakReference<>(items);
+
+            if (items != null) {
+                items.addListener(weakItemsListener);
             }
             updateItem(-1);
         }
@@ -217,7 +224,7 @@
     private final WeakListChangeListener<Integer> weakSelectedListener = new WeakListChangeListener<Integer>(selectedListener);
     private final WeakChangeListener<MultipleSelectionModel<T>> weakSelectionModelPropertyListener = new WeakChangeListener<MultipleSelectionModel<T>>(selectionModelPropertyListener);
     private final WeakListChangeListener<T> weakItemsListener = new WeakListChangeListener<T>(itemsListener);
-    private final WeakChangeListener<ObservableList<T>> weakItemsPropertyListener = new WeakChangeListener<ObservableList<T>>(itemsPropertyListener);
+    private final WeakInvalidationListener weakItemsPropertyListener = new WeakInvalidationListener(itemsPropertyListener);
     private final WeakInvalidationListener weakFocusedListener = new WeakInvalidationListener(focusedListener);
     private final WeakChangeListener<FocusModel<T>> weakFocusModelPropertyListener = new WeakChangeListener<FocusModel<T>>(focusModelPropertyListener);
 
--- a/modules/controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -25,7 +25,6 @@
 
 package javafx.scene.control.skin;
 
-import com.sun.javafx.scene.control.behavior.BehaviorBase;
 import com.sun.javafx.scene.control.behavior.ComboBoxBaseBehavior;
 import com.sun.javafx.scene.control.behavior.ComboBoxListViewBehavior;
 
@@ -46,8 +45,6 @@
 import javafx.scene.AccessibleRole;
 import javafx.scene.Node;
 import javafx.scene.Parent;
-import javafx.scene.control.Accordion;
-import javafx.scene.control.Button;
 import javafx.scene.control.ComboBox;
 import javafx.scene.control.Control;
 import javafx.scene.control.ListCell;
@@ -507,7 +504,7 @@
                 if (getSkin() instanceof ListViewSkin) {
                     ListViewSkin<?> skin = (ListViewSkin<?>)getSkin();
                     if (itemCountDirty) {
-                        skin.updateRowCount();
+                        skin.updateItemCount();
                         itemCountDirty = false;
                     }
 
--- a/modules/controls/src/main/java/javafx/scene/control/skin/ListViewSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/ListViewSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -29,7 +29,6 @@
 import java.util.List;
 
 import com.sun.javafx.scene.control.Properties;
-import com.sun.javafx.scene.control.behavior.BehaviorBase;
 import javafx.beans.InvalidationListener;
 import javafx.beans.WeakInvalidationListener;
 import javafx.collections.FXCollections;
@@ -43,7 +42,6 @@
 import javafx.scene.AccessibleAction;
 import javafx.scene.AccessibleAttribute;
 import javafx.scene.Node;
-import javafx.scene.control.Button;
 import javafx.scene.control.Control;
 import javafx.scene.control.FocusModel;
 import javafx.scene.control.IndexedCell;
@@ -159,7 +157,7 @@
             // fix for RT-37853
             getSkinnable().edit(-1);
 
-            rowCountDirty = true;
+            markItemCountDirty();
             getSkinnable().requestLayout();
         }
     };
@@ -230,7 +228,7 @@
         flow.getVbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml);
         flow.getHbar().addEventFilter(MouseEvent.MOUSE_PRESSED, ml);
 
-        updateRowCount();
+        updateItemCount();
 
         control.itemsProperty().addListener(new WeakInvalidationListener(itemsChangeListener));
 
@@ -319,12 +317,12 @@
     }
 
     /** {@inheritDoc} */
-    @Override int getItemCount() {
+    @Override protected int getItemCount() {
         return itemCount;
     }
 
     /** {@inheritDoc} */
-    @Override void updateRowCount() {
+    @Override protected void updateItemCount() {
         if (flow == null) return;
 
         int oldCount = itemCount;
@@ -452,7 +450,7 @@
             listViewItems.addListener(weakListViewItemsListener);
         }
 
-        rowCountDirty = true;
+        markItemCountDirty();
         getSkinnable().requestLayout();
     }
 
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TableCellSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TableCellSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -26,24 +26,23 @@
 package javafx.scene.control.skin;
 
 import com.sun.javafx.scene.control.behavior.BehaviorBase;
+import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.scene.Node;
-import javafx.scene.control.Accordion;
-import javafx.scene.control.Button;
-import javafx.scene.control.Control;
-import javafx.scene.control.TableCell;
+import javafx.scene.control.*;
 
 import com.sun.javafx.scene.control.behavior.TableCellBehavior;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ReadOnlyDoubleProperty;
-import javafx.scene.control.TableColumn;
 
 /**
  * Default skin implementation for the {@link TableCell} control.
  *
+ * @param <S> The type of the UI control (e.g. the type of the 'row').
+ * @param <T> The type of the content in the cell, based on its {@link TableColumn}.
  * @see TableCell
  * @since 9
  */
-public class TableCellSkin<S,T> extends TableCellSkinBase<TableCell<S,T>> {
+public class TableCellSkin<S,T> extends TableCellSkinBase<S, T, TableCell<S,T>> {
 
     /***************************************************************************
      *                                                                         *
@@ -94,12 +93,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override BooleanProperty columnVisibleProperty() {
-        return getSkinnable().getTableColumn().visibleProperty();
-    }
-
-    /** {@inheritDoc} */
-    @Override ReadOnlyDoubleProperty columnWidthProperty() {
-        return getSkinnable().getTableColumn().widthProperty();
+    @Override public ReadOnlyObjectProperty<TableColumn<S,T>> tableColumnProperty() {
+        return getSkinnable().tableColumnProperty();
     }
 }
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TableCellSkinBase.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TableCellSkinBase.java	Thu Mar 10 14:16:20 2016 -0800
@@ -30,21 +30,25 @@
 import javafx.beans.WeakInvalidationListener;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ReadOnlyDoubleProperty;
+import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.scene.Node;
 import javafx.scene.control.Accordion;
 import javafx.scene.control.Control;
 import javafx.scene.control.IndexedCell;
+import javafx.scene.control.TableColumnBase;
 import javafx.scene.shape.Rectangle;
 
 /**
  * Base skin for table cell controls, for example:
  * {@link javafx.scene.control.TableCell} and {@link javafx.scene.control.TreeTableCell}.
  *
+ * @param <S> The type of the UI control (e.g. the type of the 'row').
+ * @param <T> The type of the content in the cell, based on its {@link TableColumnBase}.
  * @see javafx.scene.control.TableCell
  * @see javafx.scene.control.TreeTableCell
  * @since 9
  */
-public abstract class TableCellSkinBase<C extends IndexedCell> extends CellSkinBase<C> {
+public abstract class TableCellSkinBase<S, T, C extends IndexedCell<T>> extends CellSkinBase<C> {
 
     /***************************************************************************
      *                                                                         *
@@ -79,13 +83,11 @@
         getSkinnable().setClip(clip);
         // --- end of RT-22038
 
-        ReadOnlyDoubleProperty columnWidthProperty = columnWidthProperty();
-        if (columnWidthProperty != null) {
-            columnWidthProperty.addListener(weakColumnWidthListener);
+        TableColumnBase<?,?> tableColumn = getTableColumn();
+        if (tableColumn != null) {
+            tableColumn.widthProperty().addListener(weakColumnWidthListener);
         }
 
-        registerChangeListener(control.visibleProperty(), e -> getSkinnable().setVisible(columnVisibleProperty().get()));
-
         if (control.getProperties().containsKey(Properties.DEFER_TO_PARENT_PREF_WIDTH)) {
             isDeferToParentForPrefWidth = true;
         }
@@ -112,11 +114,13 @@
      *                                                                         *
      **************************************************************************/
 
-    // Equivalent to tableColumn.widthProperty()
-    abstract ReadOnlyDoubleProperty columnWidthProperty();
-
-    // Equivalent to tableColumn.visibleProperty()
-    abstract BooleanProperty columnVisibleProperty();
+    /**
+     * The TableColumnBase instance that is responsible for this Cell.
+     */
+    public abstract ReadOnlyObjectProperty<? extends TableColumnBase<S,T>> tableColumnProperty();
+    public final TableColumnBase<S,T> getTableColumn() {
+        return tableColumnProperty().get();
+    }
 
 
 
@@ -128,9 +132,9 @@
 
     /** {@inheritDoc} */
     @Override public void dispose() {
-        ReadOnlyDoubleProperty columnWidthProperty = columnWidthProperty();
-        if (columnWidthProperty != null) {
-            columnWidthProperty.removeListener(weakColumnWidthListener);
+        TableColumnBase<?,T> tableColumn = getTableColumn();
+        if (tableColumn != null) {
+            tableColumn.widthProperty().removeListener(weakColumnWidthListener);
         }
 
         super.dispose();
@@ -150,6 +154,8 @@
         if (isDeferToParentForPrefWidth) {
             return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);
         }
-        return columnWidthProperty().get();
+
+        TableColumnBase<?,?> tableColumn = getTableColumn();
+        return tableColumn == null ? 0 : tableColumn.getWidth();
     }
 }
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TableRowSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TableRowSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -101,6 +101,22 @@
                 }
             }
         });
+
+        DoubleProperty fixedCellSizeProperty = getTableView().fixedCellSizeProperty();
+        if (fixedCellSizeProperty != null) {
+            registerChangeListener(fixedCellSizeProperty, e -> {
+                fixedCellSize = fixedCellSizeProperty.get();
+                fixedCellSizeEnabled = fixedCellSize > 0;
+            });
+            fixedCellSize = fixedCellSizeProperty.get();
+            fixedCellSizeEnabled = fixedCellSize > 0;
+
+            // JDK-8144500:
+            // When in fixed cell size mode, we must listen to the width of the virtual flow, so
+            // that when it changes, we can appropriately add / remove cells that may or may not
+            // be required (because we remove all cells that are not visible).
+            registerChangeListener(getVirtualFlow().widthProperty(), e -> control.requestLayout());
+        }
     }
 
 
@@ -128,12 +144,12 @@
                 // (selectedCells could be big, cellsMap is much smaller)
                 List<Node> selection = new ArrayList<>();
                 int index = getSkinnable().getIndex();
-                for (TablePosition<T,?> pos : getVirtualFlowOwner().getSelectionModel().getSelectedCells()) {
+                for (TablePosition<T,?> pos : getTableView().getSelectionModel().getSelectedCells()) {
                     if (pos.getRow() == index) {
                         TableColumn<T,?> column = pos.getTableColumn();
                         if (column == null) {
                             /* This is the row-based case */
-                            column = getVirtualFlowOwner().getVisibleLeafColumn(0);
+                            column = getTableView().getVisibleLeafColumn(0);
                         }
                         TableCell<T,?> cell = cellsMap.get(column).get();
                         if (cell != null) selection.add(cell);
@@ -143,19 +159,19 @@
             }
             case CELL_AT_ROW_COLUMN: {
                 int colIndex = (Integer)parameters[1];
-                TableColumn<T,?> column = getVirtualFlowOwner().getVisibleLeafColumn(colIndex);
+                TableColumn<T,?> column = getTableView().getVisibleLeafColumn(colIndex);
                 if (cellsMap.containsKey(column)) {
                     return cellsMap.get(column).get();
                 }
                 return null;
             }
             case FOCUS_ITEM: {
-                TableViewFocusModel<T> fm = getVirtualFlowOwner().getFocusModel();
+                TableViewFocusModel<T> fm = getTableView().getFocusModel();
                 TablePosition<T,?> focusedCell = fm.getFocusedCell();
                 TableColumn<T,?> column = focusedCell.getTableColumn();
                 if (column == null) {
                     /* This is the row-based case */
-                    column = getVirtualFlowOwner().getVisibleLeafColumn(0);
+                    column = getTableView().getVisibleLeafColumn(0);
                 }
                 if (cellsMap.containsKey(column)) {
                     return cellsMap.get(column).get();
@@ -175,7 +191,7 @@
      **************************************************************************/
 
     /** {@inheritDoc} */
-    @Override TableCell<T, ?> getCell(TableColumnBase tcb) {
+    @Override protected TableCell<T, ?> createCell(TableColumnBase tcb) {
         TableColumn tableColumn = (TableColumn<T,?>) tcb;
         TableCell cell = (TableCell) tableColumn.getCellFactory().call(tableColumn);
 
@@ -188,37 +204,21 @@
     }
 
     /** {@inheritDoc} */
-    @Override ObservableList<TableColumn<T, ?>> getVisibleLeafColumns() {
-        return getVirtualFlowOwner().getVisibleLeafColumns();
+    @Override protected ObservableList<TableColumn<T, ?>> getVisibleLeafColumns() {
+        return getTableView().getVisibleLeafColumns();
     }
 
     /** {@inheritDoc} */
-    @Override void updateCell(TableCell<T, ?> cell, TableRow<T> row) {
+    @Override protected void updateCell(TableCell<T, ?> cell, TableRow<T> row) {
         cell.updateTableRow(row);
     }
 
     /** {@inheritDoc} */
-    @Override DoubleProperty fixedCellSizeProperty() {
-        return getVirtualFlowOwner().fixedCellSizeProperty();
-    }
-
-    /** {@inheritDoc} */
-    @Override boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc) {
-        return tableViewSkin == null ? false : tableViewSkin.isColumnPartiallyOrFullyVisible((TableColumn)tc);
-    }
-
-    /** {@inheritDoc} */
-    @Override TableColumn<T, ?> getTableColumnBase(TableCell<T, ?> cell) {
+    @Override protected TableColumn<T, ?> getTableColumn(TableCell<T, ?> cell) {
         return cell.getTableColumn();
     }
 
-    /** {@inheritDoc} */
-    @Override ObjectProperty<Node> graphicProperty() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override TableView<T> getVirtualFlowOwner() {
+    private TableView<T> getTableView() {
         return getSkinnable().getTableView();
     }
 
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TableRowSkinBase.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TableRowSkinBase.java	Thu Mar 10 14:16:20 2016 -0800
@@ -31,6 +31,7 @@
 import java.util.*;
 
 import com.sun.javafx.PlatformUtil;
+import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
 import javafx.animation.FadeTransition;
 import javafx.beans.property.DoubleProperty;
 import javafx.beans.property.ObjectProperty;
@@ -39,6 +40,7 @@
 import javafx.collections.WeakListChangeListener;
 import javafx.css.StyleOrigin;
 import javafx.css.StyleableObjectProperty;
+import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
 import javafx.scene.Parent;
@@ -88,14 +90,14 @@
     /*
      * This is rather hacky - but it is a quick workaround to resolve the
      * issue that we don't know maximum width of a disclosure node for a given
-     * TreeView. If we don't know the maximum width, we have no way to ensure
-     * consistent indentation for a given TreeView.
+     * control. If we don't know the maximum width, we have no way to ensure
+     * consistent indentation.
      *
      * To work around this, we create a single WeakHashMap to store a max
-     * disclosureNode width per TreeView. We use WeakHashMap to help prevent
+     * disclosureNode width per TableColumnBase. We use WeakHashMap to help prevent
      * any memory leaks.
      */
-    static final Map<Control, Double> maxDisclosureWidthMap = new WeakHashMap<Control, Double>();
+    static final Map<TableColumnBase<?,?>, Double> maxDisclosureWidthMap = new WeakHashMap<>();
 
     // Specifies the number of times we will call 'recreateCells()' before we blow
     // out the cellsMap structure and rebuild all cells. This helps to prevent
@@ -132,8 +134,8 @@
     boolean isDirty = false;
     boolean updateCells = false;
 
-    private double fixedCellSize;
-    private boolean fixedCellSizeEnabled;
+    double fixedCellSize;
+    boolean fixedCellSizeEnabled;
 
 
 
@@ -177,21 +179,6 @@
                 requestCellUpdate();
             }
         });
-
-        if (fixedCellSizeProperty() != null) {
-            registerChangeListener(fixedCellSizeProperty(), e -> {
-                fixedCellSize = fixedCellSizeProperty().get();
-                fixedCellSizeEnabled = fixedCellSize > 0;
-            });
-            fixedCellSize = fixedCellSizeProperty().get();
-            fixedCellSizeEnabled = fixedCellSize > 0;
-
-            // JDK-8144500:
-            // When in fixed cell size mode, we must listen to the width of the virtual flow, so
-            // that when it changes, we can appropriately add / remove cells that may or may not
-            // be required (because we remove all cells that are not visible).
-            registerChangeListener(getVirtualFlow().widthProperty(), e -> control.requestLayout());
-        }
     }
 
 
@@ -208,7 +195,7 @@
     };
 
     private WeakListChangeListener<TableColumnBase> weakVisibleLeafColumnsListener =
-            new WeakListChangeListener<TableColumnBase>(visibleLeafColumnsListener);
+            new WeakListChangeListener<>(visibleLeafColumnsListener);
 
 
 
@@ -219,36 +206,47 @@
      **************************************************************************/
 
     /**
+     * Creates a new cell instance that is suitable for representing the given table column instance.
+     */
+    protected abstract R createCell(TableColumnBase<T,?> tc);
+
+    /**
+     * A method to allow the given cell to be told that it is a member of the given row.
+     * How this is implemented is dependent on the actual cell implementation.
+     * @param cell The cell for which we want to inform it of its owner row.
+     * @param row The row which will be set on the given cell.
+     */
+    protected abstract void updateCell(R cell, C row);
+
+    /**
+     * Returns the {@link TableColumnBase} instance for the given cell instance.
+     * @param cell The cell for which a TableColumn is desired.
+     */
+    protected abstract TableColumnBase<T,?> getTableColumn(R cell);
+
+    /**
+     * Returns an unmodifiable list containing the currently visible leaf columns.
+     */
+    @ReturnsUnmodifiableCollection
+    protected abstract ObservableList<? extends TableColumnBase/*<T,?>*/> getVisibleLeafColumns();
+
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Public Methods                                                          *
+     *                                                                         *
+     **************************************************************************/
+
+    /**
      * Returns the graphic to draw on the inside of the disclosure node. Null
      * is acceptable when no graphic should be shown. Commonly this is the
      * graphic associated with a TreeItem (i.e. treeItem.getGraphic()), rather
      * than a graphic associated with a cell.
      */
-    abstract ObjectProperty<Node> graphicProperty();
-
-    // return TableView / TreeTableView / etc
-    abstract Control getVirtualFlowOwner();
-
-    abstract ObservableList<? extends TableColumnBase/*<T,?>*/> getVisibleLeafColumns();
-
-    // cell.updateTableRow(skinnable); (i.e cell.updateTableRow(row))
-    abstract void updateCell(R cell, C row);
-
-    abstract DoubleProperty fixedCellSizeProperty();
-
-    abstract boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc);
-
-    abstract R getCell(TableColumnBase tc);
-
-    abstract TableColumnBase<T,?> getTableColumnBase(R cell);
-
-
-
-    /***************************************************************************
-     *                                                                         *
-     * Public Methods                                                          *
-     *                                                                         *
-     **************************************************************************/
+    protected ObjectProperty<Node> graphicProperty() {
+        return null;
+    }
 
     /** {@inheritDoc} */
     @Override protected void layoutChildren(double x, final double y, final double w, final double h) {
@@ -287,9 +285,8 @@
             leftMargin = indentationLevel * indentationPerLevel;
 
             // position the disclosure node so that it is at the proper indent
-            Control c = getVirtualFlowOwner();
-            final double defaultDisclosureWidth = maxDisclosureWidthMap.containsKey(c) ?
-                maxDisclosureWidthMap.get(c) : 0;
+            final double defaultDisclosureWidth = maxDisclosureWidthMap.containsKey(treeColumn) ?
+                maxDisclosureWidthMap.get(treeColumn) : 0;
             disclosureWidth = defaultDisclosureWidth;
 
             disclosureNode = getDisclosureNode();
@@ -299,7 +296,7 @@
                 if (disclosureVisible) {
                     disclosureWidth = disclosureNode.prefWidth(h);
                     if (disclosureWidth > defaultDisclosureWidth) {
-                        maxDisclosureWidthMap.put(c, disclosureWidth);
+                        maxDisclosureWidthMap.put(treeColumn, disclosureWidth);
 
                         // RT-36359: The recorded max width of the disclosure node
                         // has increased. We need to go back and request all
@@ -341,7 +338,7 @@
 
         for (int column = 0, max = cells.size(); column < max; column++) {
             R tableCell = cells.get(column);
-            TableColumnBase<T, ?> tableColumn = getTableColumnBase(tableCell);
+            TableColumnBase<T, ?> tableColumn = getTableColumn(tableCell);
 
             boolean isVisible = true;
             if (fixedCellSizeEnabled) {
@@ -495,12 +492,6 @@
         return true;
     }
 
-    TableColumnBase<T,?> getVisibleLeafColumn(int column) {
-        final List<? extends TableColumnBase/*<T,?>*/> visibleLeafColumns = getVisibleLeafColumns();
-        if (column < 0 || column >= visibleLeafColumns.size()) return null;
-        return visibleLeafColumns.get(column);
-    }
-
     void updateCells(boolean resetChildren) {
         // To avoid a potential memory leak (when the TableColumns in the
         // TableView are created/inserted/removed/deleted, we have a 'refresh
@@ -538,7 +529,7 @@
             if (cell == null) {
                 // if the cell is null it means we don't have it in cache and
                 // need to create it
-                cell = createCell(col);
+                cell = createCellAndCache(col);
             }
 
             updateCell(cell, skinnable);
@@ -554,7 +545,7 @@
             List<Node> toRemove = new ArrayList<>();
             for (Node cell : getChildren()) {
                 if (! (cell instanceof IndexedCell)) continue;
-                if (!getTableColumnBase((R)cell).isVisible()) {
+                if (!getTableColumn((R)cell).isVisible()) {
                     toRemove.add(cell);
                 }
             }
@@ -564,7 +555,7 @@
         }
     }
 
-    private VirtualFlow<C> getVirtualFlow() {
+    VirtualFlow<C> getVirtualFlow() {
         Parent p = getSkinnable();
         while (p != null) {
             if (p instanceof VirtualFlow) {
@@ -575,6 +566,7 @@
         return null;
     }
 
+    /** {@inheritDoc} */
     @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
         double prefWidth = 0.0;
 
@@ -586,6 +578,7 @@
         return prefWidth;
     }
 
+    /** {@inheritDoc} */
     @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         if (fixedCellSizeEnabled) {
             return fixedCellSize;
@@ -615,6 +608,7 @@
         return ph;
     }
 
+    /** {@inheritDoc} */
     @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         if (fixedCellSizeEnabled) {
             return fixedCellSize;
@@ -642,6 +636,7 @@
         return minHeight;
     }
 
+    /** {@inheritDoc} */
     @Override protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
         if (fixedCellSizeEnabled) {
             return fixedCellSize;
@@ -668,6 +663,29 @@
      *                                                                         *
      **************************************************************************/
 
+    private boolean isColumnPartiallyOrFullyVisible(TableColumnBase col) {
+        if (col == null || !col.isVisible()) return false;
+
+        final VirtualFlow<?> virtualFlow = getVirtualFlow();
+        double scrollX = virtualFlow == null ? 0.0 : virtualFlow.getHbar().getValue();
+
+        // work out where this column header is, and it's width (start -> end)
+        double start = 0;
+        final ObservableList<? extends TableColumnBase> visibleLeafColumns = getVisibleLeafColumns();
+        for (int i = 0, max = visibleLeafColumns.size(); i < max; i++) {
+            TableColumnBase<?,?> c = visibleLeafColumns.get(i);
+            if (c.equals(col)) break;
+            start += c.getWidth();
+        }
+        double end = start + col.getWidth();
+
+        // determine the width of the table
+        final Insets padding = getSkinnable().getPadding();
+        double headerWidth = getSkinnable().getWidth() - padding.getLeft() + padding.getRight();
+
+        return (start >= scrollX || end > scrollX) && (start < (headerWidth + scrollX) || end <= (headerWidth + scrollX));
+    }
+
     private void requestCellUpdate() {
         updateCells = true;
         getSkinnable().requestLayout();
@@ -702,7 +720,7 @@
 
         ObservableList<? extends TableColumnBase/*<T,?>*/> columns = getVisibleLeafColumns();
 
-        cellsMap = new WeakHashMap<TableColumnBase, Reference<R>>(columns.size());
+        cellsMap = new WeakHashMap<>(columns.size());
         fullRefreshCounter = DEFAULT_FULL_REFRESH_COUNTER;
         getChildren().clear();
 
@@ -713,16 +731,16 @@
 
             // create a TableCell for this column and store it in the cellsMap
             // for future use
-            createCell(col);
+            createCellAndCache(col);
         }
     }
 
-    private R createCell(TableColumnBase col) {
+    private R createCellAndCache(TableColumnBase<T,?> col) {
         // we must create a TableCell for this table column
-        R cell = getCell(col);
+        R cell = createCell(col);
 
         // and store this in our HashMap until needed
-        cellsMap.put(col, new WeakReference<R>(cell));
+        cellsMap.put(col, new WeakReference<>(cell));
 
         return cell;
     }
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TableViewSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TableViewSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -224,7 +224,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override int getItemCount() {
+    @Override protected int getItemCount() {
         TableView<T> tableView = getSkinnable();
         return tableView.getItems() == null ? 0 : tableView.getItems().size();
     }
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TableViewSkinBase.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TableViewSkinBase.java	Thu Mar 10 14:16:20 2016 -0800
@@ -210,7 +210,7 @@
             ((TableView)getSkinnable()).edit(-1, null);
         }
 
-        rowCountDirty = true;
+        markItemCountDirty();
         getSkinnable().requestLayout();
     };
 
@@ -562,7 +562,8 @@
         return tableHeaderRow;
     }
 
-    @Override void updateRowCount() {
+    /** {@inheritDoc} */
+    @Override protected void updateItemCount() {
         updatePlaceholderRegionVisibility();
 
         int oldCount = itemCount;
@@ -579,7 +580,7 @@
             needCellsRecreated = true;
             forceCellRecreate = false;
         } else if (newCount != oldCount) {
-            // FIXME updateRowCount is called _a lot_. Perhaps we can make rebuildCells
+            // FIXME updateItemCount is called _a lot_. Perhaps we can make rebuildCells
             // smarter. Imagine if items has one million items added - do we really
             // need to rebuildCells a million times? Maybe this is better now that
             // we do rebuildCells instead of recreateCells.
@@ -659,7 +660,7 @@
             newList.addListener(weakRowCountListener);
         }
 
-        rowCountDirty = true;
+        markItemCountDirty();
         getSkinnable().requestLayout();
     }
 
@@ -758,28 +759,6 @@
                 || (! isFocusDriven && sm.getSelectedIndex() == index);
     }
 
-    boolean isColumnPartiallyOrFullyVisible(TC col) {
-        if (col == null || !col.isVisible()) return false;
-
-        double scrollX = flow.getHbar().getValue();
-
-        // work out where this column header is, and it's width (start -> end)
-        double start = 0;
-        final ObservableList<? extends TC> visibleLeafColumns = getVisibleLeafColumns();
-        for (int i = 0, max = visibleLeafColumns.size(); i < max; i++) {
-            TableColumnBase<S,?> c = visibleLeafColumns.get(i);
-            if (c.equals(col)) break;
-            start += c.getWidth();
-        }
-        double end = start + col.getWidth();
-
-        // determine the width of the table
-        final Insets padding = getSkinnable().getPadding();
-        double headerWidth = getSkinnable().getWidth() - padding.getLeft() + padding.getRight();
-
-        return (start >= scrollX || end > scrollX) && (start < (headerWidth + scrollX) || end <= (headerWidth + scrollX));
-    }
-
     /**
      * Keeps track of how many leaf columns are currently visible in this table.
      */
@@ -863,7 +842,7 @@
     }
 
     private void refreshView() {
-        rowCountDirty = true;
+        markItemCountDirty();
         Control c = getSkinnable();
         if (c != null) {
             c.requestLayout();
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TreeTableCellSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TreeTableCellSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -28,24 +28,19 @@
 import com.sun.javafx.scene.control.behavior.BehaviorBase;
 import com.sun.javafx.scene.control.behavior.TreeTableCellBehavior;
 import java.util.Map;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.ReadOnlyDoubleProperty;
+import javafx.beans.property.ReadOnlyObjectProperty;
 import javafx.scene.Node;
-import javafx.scene.control.Button;
-import javafx.scene.control.Control;
-import javafx.scene.control.TreeItem;
-import javafx.scene.control.TreeTableCell;
-import javafx.scene.control.TreeTableColumn;
-import javafx.scene.control.TreeTableRow;
-import javafx.scene.control.TreeTableView;
+import javafx.scene.control.*;
 
 /**
  * Default skin implementation for the {@link TreeTableCell} control.
  *
+ * @param <S> The type of the UI control (e.g. the type of the 'row'), this is wrapped in a TreeItem.
+ * @param <T> The type of the content in the cell, based on its {@link TreeTableColumn}.
  * @see TreeTableCell
  * @since 9
  */
-public class TreeTableCellSkin<S,T> extends TableCellSkinBase<TreeTableCell<S,T>> {
+public class TreeTableCellSkin<S,T> extends TableCellSkinBase<TreeItem<S>, T, TreeTableCell<S,T>> {
 
     /***************************************************************************
      *                                                                         *
@@ -104,13 +99,8 @@
      **************************************************************************/
 
     /** {@inheritDoc} */
-    @Override BooleanProperty columnVisibleProperty() {
-        return getSkinnable().getTableColumn().visibleProperty();
-    }
-
-    /** {@inheritDoc} */
-    @Override ReadOnlyDoubleProperty columnWidthProperty() {
-        return getSkinnable().getTableColumn().widthProperty();
+    @Override public ReadOnlyObjectProperty<TreeTableColumn<S,T>> tableColumnProperty() {
+        return getSkinnable().tableColumnProperty();
     }
 
     /** {@inheritDoc} */
@@ -154,8 +144,8 @@
         leftPadding += nodeLevel * indentPerLevel;
 
         // add in the width of the disclosure node, if one exists
-        Map<Control, Double> mdwp = TableRowSkinBase.maxDisclosureWidthMap;
-        leftPadding += mdwp.containsKey(treeTable) ? mdwp.get(treeTable) : 0;
+        Map<TableColumnBase<?,?>, Double> mdwp = TableRowSkinBase.maxDisclosureWidthMap;
+        leftPadding += mdwp.containsKey(treeColumn) ? mdwp.get(treeColumn) : 0;
 
         // adding in the width of the graphic on the tree item
         Node graphic = treeItem.getGraphic();
@@ -163,14 +153,4 @@
 
         return leftPadding;
     }
-
-    /** {@inheritDoc} */
-    @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
-        if (isDeferToParentForPrefWidth) {
-            // RT-27167: we must take into account the disclosure node and the
-            // indentation (which is not taken into account by the LabeledSkinBase.
-            return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);
-        }
-        return columnWidthProperty().get();
-    }
 }
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TreeTableRowSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TreeTableRowSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -121,6 +121,22 @@
             isDirty = true;
             getSkinnable().requestLayout();
         });
+
+        DoubleProperty fixedCellSizeProperty = getTreeTableView().fixedCellSizeProperty();
+        if (fixedCellSizeProperty != null) {
+            registerChangeListener(fixedCellSizeProperty, e -> {
+                fixedCellSize = fixedCellSizeProperty.get();
+                fixedCellSizeEnabled = fixedCellSize > 0;
+            });
+            fixedCellSize = fixedCellSizeProperty.get();
+            fixedCellSizeEnabled = fixedCellSize > 0;
+
+            // JDK-8144500:
+            // When in fixed cell size mode, we must listen to the width of the virtual flow, so
+            // that when it changes, we can appropriately add / remove cells that may or may not
+            // be required (because we remove all cells that are not visible).
+            registerChangeListener(getVirtualFlow().widthProperty(), e -> control.requestLayout());
+        }
     }
 
 
@@ -228,7 +244,7 @@
      **************************************************************************/
 
     /** {@inheritDoc} */
-    @Override TreeTableCell<T, ?> getCell(TableColumnBase tcb) {
+    @Override protected TreeTableCell<T, ?> createCell(TableColumnBase tcb) {
         TreeTableColumn tableColumn = (TreeTableColumn<T,?>) tcb;
         TreeTableCell cell = (TreeTableCell) tableColumn.getCellFactory().call(tableColumn);
 
@@ -255,12 +271,12 @@
 
     /** {@inheritDoc} */
     @Override TableColumnBase getTreeColumn() {
-        return getSkinnable().getTreeTableView().getTreeColumn();
+        return getTreeTableView().getTreeColumn();
     }
 
     /** {@inheritDoc} */
     @Override int getIndentationLevel(TreeTableRow<T> control) {
-        return control.getTreeTableView().getTreeItemLevel(control.getTreeItem());
+        return getTreeTableView().getTreeItemLevel(control.getTreeItem());
     }
 
     /** {@inheritDoc} */
@@ -278,31 +294,26 @@
     }
 
     @Override boolean isShowRoot() {
-        return getSkinnable().getTreeTableView().isShowRoot();
+        return getTreeTableView().isShowRoot();
     }
 
     /** {@inheritDoc} */
-    @Override ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {
-        return getSkinnable().getTreeTableView().getVisibleLeafColumns();
+    @Override protected ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {
+        return getTreeTableView().getVisibleLeafColumns();
     }
 
     /** {@inheritDoc} */
-    @Override void updateCell(TreeTableCell<T, ?> cell, TreeTableRow<T> row) {
+    @Override protected void updateCell(TreeTableCell<T, ?> cell, TreeTableRow<T> row) {
         cell.updateTreeTableRow(row);
     }
 
     /** {@inheritDoc} */
-    @Override boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc) {
-        return treeTableViewSkin == null ? false : treeTableViewSkin.isColumnPartiallyOrFullyVisible(tc);
-    }
-
-    /** {@inheritDoc} */
-    @Override TreeTableColumn<T, ?> getTableColumnBase(TreeTableCell cell) {
+    @Override protected TreeTableColumn<T, ?> getTableColumn(TreeTableCell cell) {
         return cell.getTableColumn();
     }
 
     /** {@inheritDoc} */
-    @Override ObjectProperty<Node> graphicProperty() {
+    @Override protected ObjectProperty<Node> graphicProperty() {
         TreeTableRow<T> treeTableRow = getSkinnable();
         if (treeTableRow == null) return null;
         if (treeItem == null) return null;
@@ -310,16 +321,6 @@
         return treeItem.graphicProperty();
     }
 
-    /** {@inheritDoc} */
-    @Override Control getVirtualFlowOwner() {
-        return getSkinnable().getTreeTableView();
-    }
-
-    /** {@inheritDoc} */
-    @Override DoubleProperty fixedCellSizeProperty() {
-        return getSkinnable().getTreeTableView().fixedCellSizeProperty();
-    }
-
     private void updateTreeItem() {
         if (treeItem != null) {
             treeItem.graphicProperty().removeListener(graphicListener);
@@ -330,6 +331,10 @@
         }
     }
 
+    private TreeTableView<T> getTreeTableView() {
+        return getSkinnable().getTreeTableView();
+    }
+
     private void updateDisclosureNodeAndGraphic() {
         if (getSkinnable().isEmpty()) return;
 
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TreeTableViewSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -29,7 +29,6 @@
 import com.sun.javafx.scene.control.Properties;
 import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList;
 
-import com.sun.javafx.scene.control.behavior.BehaviorBase;
 import com.sun.javafx.scene.control.skin.Utils;
 import javafx.event.WeakEventHandler;
 import javafx.scene.control.*;
@@ -90,7 +89,7 @@
             // no event being fired to the skin to be informed that the items
             // had changed. So, here we just watch for the case where the number
             // of items being added is equal to the number of items being removed.
-            rowCountDirty = true;
+            markItemCountDirty();
             getSkinnable().requestLayout();
         } else if (e.getEventType().equals(TreeItem.valueChangedEvent())) {
             // Fix for RT-14971 and RT-15338.
@@ -102,7 +101,7 @@
             EventType<?> eventType = e.getEventType();
             while (eventType != null) {
                 if (eventType.equals(TreeItem.<T>expandedItemCountChangeEvent())) {
-                    rowCountDirty = true;
+                    markItemCountDirty();
                     getSkinnable().requestLayout();
                     break;
                 }
@@ -189,10 +188,10 @@
                 getRoot().setExpanded(true);
             }
             // update the item count in the flow and behavior instances
-            updateRowCount();
+            updateItemCount();
         });
         registerChangeListener(control.rowFactoryProperty(), e -> flow.recreateCells());
-        registerChangeListener(control.expandedItemCountProperty(), e -> rowCountDirty = true);
+        registerChangeListener(control.expandedItemCountProperty(), e -> markItemCountDirty());
         registerChangeListener(control.fixedCellSizeProperty(), e -> flow.setFixedCellSize(getSkinnable().getFixedCellSize()));
     }
 
@@ -322,7 +321,7 @@
             getRoot().addEventHandler(TreeItem.<T>treeNotificationEvent(), weakRootListener);
         }
 
-        updateRowCount();
+        updateItemCount();
     }
 
     /** {@inheritDoc} */
@@ -474,7 +473,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override int getItemCount() {
+    @Override protected int getItemCount() {
         return getSkinnable().getExpandedItemCount();
     }
 
@@ -487,7 +486,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override void updateRowCount() {
+    @Override protected void updateItemCount() {
         updatePlaceholderRegionVisibility();
 
         tableBackingList.resetSize();
--- a/modules/controls/src/main/java/javafx/scene/control/skin/TreeViewSkin.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/TreeViewSkin.java	Thu Mar 10 14:16:20 2016 -0800
@@ -26,7 +26,6 @@
 package javafx.scene.control.skin;
 
 import com.sun.javafx.scene.control.Properties;
-import com.sun.javafx.scene.control.behavior.BehaviorBase;
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
 import javafx.beans.WeakInvalidationListener;
@@ -115,7 +114,7 @@
             // no event being fired to the skin to be informed that the items
             // had changed. So, here we just watch for the case where the number
             // of items being added is equal to the number of items being removed.
-            rowCountDirty = true;
+            markItemCountDirty();
             getSkinnable().requestLayout();
         } else if (e.getEventType().equals(TreeItem.valueChangedEvent())) {
             // Fix for RT-14971 and RT-15338.
@@ -127,7 +126,7 @@
             EventType<?> eventType = e.getEventType();
             while (eventType != null) {
                 if (eventType.equals(TreeItem.<T>expandedItemCountChangeEvent())) {
-                    rowCountDirty = true;
+                    markItemCountDirty();
                     getSkinnable().requestLayout();
                     break;
                 }
@@ -215,12 +214,12 @@
                 getRoot().setExpanded(true);
             }
             // update the item count in the flow and behavior instances
-            updateRowCount();
+            updateItemCount();
         });
         registerChangeListener(control.cellFactoryProperty(), e -> flow.recreateCells());
         registerChangeListener(control.fixedCellSizeProperty(), e -> flow.setFixedCellSize(getSkinnable().getFixedCellSize()));
 
-        updateRowCount();
+        updateItemCount();
     }
 
 
@@ -397,16 +396,16 @@
             getRoot().addEventHandler(TreeItem.<T>treeNotificationEvent(), weakRootListener);
         }
 
-        updateRowCount();
+        updateItemCount();
     }
 
     /** {@inheritDoc} */
-    @Override int getItemCount() {
+    @Override protected int getItemCount() {
         return getSkinnable().getExpandedItemCount();
     }
 
     /** {@inheritDoc} */
-    @Override void updateRowCount() {
+    @Override protected void updateItemCount() {
 //        int oldCount = flow.getCellCount();
         int newCount = getItemCount();
 
--- a/modules/controls/src/main/java/javafx/scene/control/skin/VirtualContainerBase.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/skin/VirtualContainerBase.java	Thu Mar 10 14:16:20 2016 -0800
@@ -25,19 +25,17 @@
 
 package javafx.scene.control.skin;
 
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.scene.control.Cell;
 import javafx.scene.control.Control;
 import javafx.scene.control.IndexedCell;
 import javafx.scene.control.ScrollToEvent;
 import javafx.scene.control.SkinBase;
-import javafx.util.Callback;
 
 /**
  * Parent class to control skins whose contents are virtualized and scrollable.
  * This class handles the interaction with the VirtualFlow class, which is the
  * main class handling the virtualization of the contents of this container.
+ *
+ * @since 9
  */
 public abstract class VirtualContainerBase<C extends Control, I extends IndexedCell> extends SkinBase<C> {
 
@@ -47,7 +45,7 @@
      *                                                                         *
      **************************************************************************/
 
-    boolean rowCountDirty;
+    private boolean itemCountDirty;
 
     /**
      * The virtualized container which handles the layout and scrolling of
@@ -74,10 +72,10 @@
         control.addEventHandler(ScrollToEvent.scrollToTopIndex(), event -> {
             // Fix for RT-24630: The row count in VirtualFlow was incorrect
             // (normally zero), so the scrollTo call was misbehaving.
-            if (rowCountDirty) {
+            if (itemCountDirty) {
                 // update row count before we do a scroll
-                updateRowCount();
-                rowCountDirty = false;
+                updateItemCount();
+                itemCountDirty = false;
             }
             flow.scrollToTop(event.getScrollTarget());
         });
@@ -95,9 +93,14 @@
      * Returns the total number of items in this container, including those
      * that are currently hidden because they are out of view.
      */
-    abstract int getItemCount();
+    protected abstract int getItemCount();
 
-    abstract void updateRowCount();
+    /**
+     * This method is called when it is possible that the item count has changed (i.e. scrolling has occurred,
+     * the control has resized, etc). This method should recalculate the item count and store that for future
+     * use by the {@link #getItemCount} method.
+     */
+    protected abstract void updateItemCount();
 
 
 
@@ -107,6 +110,13 @@
      *                                                                         *
      **************************************************************************/
 
+    /**
+     * Call this method to indicate that the item count should be updated on the next pulse.
+     */
+    protected final void markItemCountDirty() {
+        itemCountDirty = true;
+    }
+
     /** {@inheritDoc} */
     @Override protected void layoutChildren(double x, double y, double w, double h) {
         checkState();
@@ -147,9 +157,9 @@
     }
 
     void checkState() {
-        if (rowCountDirty) {
-            updateRowCount();
-            rowCountDirty = false;
+        if (itemCountDirty) {
+            updateItemCount();
+            itemCountDirty = false;
         }
     }
 }
--- a/modules/graphics/src/test/java/netscape/javascript/JSObjectTest.java	Thu Mar 10 01:24:59 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package netscape.javascript;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Test for JSObject class.
- */
-public class JSObjectTest {
-
-    @Test
-    public void testGetWindow() {
-        try {
-            JSObject.getWindow(null);
-            fail("Did not get the expected JSException");
-        } catch (JSException ex) {
-            String msg = ex.getMessage();
-            assertNotNull(msg);
-            assertTrue(msg.startsWith("Unexpected error:"));
-            assertTrue(msg.endsWith("plugin.jar"));
-        }
-    }
-
-    @Test
-    public void testCall() {
-        JSObject jso = new JSObject() {
-            @Override
-            public Object call(String methodName, Object... args) throws JSException {
-                List<String> list = new ArrayList<>();
-                if (args != null) {
-                    for (Object arg : args) {
-                        list.add((String)arg);
-                    }
-                }
-                return list;
-            }
-
-            @Override
-            public Object eval(String s) throws JSException {
-                throw new UnsupportedOperationException("Not supported yet.");
-            }
-
-            @Override
-            public Object getMember(String name) throws JSException {
-                throw new UnsupportedOperationException("Not supported yet.");
-            }
-
-            @Override
-            public void setMember(String name, Object value) throws JSException {
-                throw new UnsupportedOperationException("Not supported yet.");
-            }
-
-            @Override
-            public void removeMember(String name) throws JSException {
-                throw new UnsupportedOperationException("Not supported yet.");
-            }
-
-            @Override
-            public Object getSlot(int index) throws JSException {
-                throw new UnsupportedOperationException("Not supported yet.");
-            }
-
-            @Override
-            public void setSlot(int index, Object value) throws JSException {
-                throw new UnsupportedOperationException("Not supported yet.");
-            }
-        };
-
-        List<String> list;
-
-        list = (List<String>)jso.call("");
-        assertTrue(list.isEmpty());
-
-        list = (List<String>)jso.call("", new Object[0]);
-        assertTrue(list.isEmpty());
-
-        list = (List<String>)jso.call("", (Object[])null);
-        assertTrue(list.isEmpty());
-
-        list = (List<String>)jso.call("", null);
-        assertTrue(list.isEmpty());
-
-        list = (List<String>)jso.call("", (Object)null);
-        assertFalse(list.isEmpty());
-        assertEquals(1, list.size());
-        assertNull(list.get(0));
-
-        list = (List<String>)jso.call("", "str1");
-        assertFalse(list.isEmpty());
-        assertEquals(1, list.size());
-        assertEquals("str1", list.get(0));
-
-        list = (List<String>)jso.call("", new Object[] { "str1" });
-        assertFalse(list.isEmpty());
-        assertEquals(1, list.size());
-        assertEquals("str1", list.get(0));
-
-        list = (List<String>)jso.call("", "str1", "str2");
-        assertFalse(list.isEmpty());
-        assertEquals(2, list.size());
-        assertEquals("str1", list.get(0));
-        assertEquals("str2", list.get(1));
-
-        list = (List<String>)jso.call("", new Object[] { "str1", "str2" });
-        assertFalse(list.isEmpty());
-        assertEquals(2, list.size());
-        assertEquals("str1", list.get(0));
-        assertEquals("str2", list.get(1));
-    }
-
-}
--- a/modules/graphics/src/test/java/test/javafx/print/JobSettingsTest.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/graphics/src/test/java/test/javafx/print/JobSettingsTest.java	Thu Mar 10 14:16:20 2016 -0800
@@ -214,7 +214,23 @@
      System.out.println("# of papers="+s.size());
      if (s != null) {
         for (Paper newPaper : s) {
-            PageLayout newPL = printer.createPageLayout(newPaper,  pagelayout.getPageOrientation(),   pagelayout.getTopMargin(), pagelayout.getBottomMargin(), pagelayout.getLeftMargin(), pagelayout.getRightMargin());
+            System.out.println("newPaper= "+newPaper);
+
+            double lm = pagelayout.getLeftMargin();
+            double rm = pagelayout.getRightMargin();
+            double tm = pagelayout.getTopMargin();
+            double bm = pagelayout.getBottomMargin();
+
+            if ((lm + rm > newPaper.getWidth()) ||
+                (tm + bm > newPaper.getHeight())) {
+                // margins exceed this paper, so make them smaller, say 10% of dimension
+                lm = rm = newPaper.getWidth() * 0.10;
+                tm = bm = newPaper.getHeight() * 0.10;
+            }
+
+            PageLayout newPL = printer.createPageLayout(newPaper,
+                pagelayout.getPageOrientation(),
+                tm, bm, lm, rm);
             System.out.println("newPaper= "+newPaper);
             js.setPageLayout(newPL);
             pagelayout = js.getPageLayout();
--- a/modules/web/src/main/native/Source/WebCore/TargetJava.pri	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/TargetJava.pri	Thu Mar 10 14:16:20 2016 -0800
@@ -224,14 +224,14 @@
     }
 
     linux-*|solaris-g++* {
-        QMAKE_LFLAGS += -Xlinker -version-script=$$PWD/mapfile-vers
+        QMAKE_LFLAGS += -Xlinker -version-script=$$PWD/mapfile-vers -Xlinker --no-undefined
 
-        # just for build debug: force verboce output from linker 
+        # just for build debug: force verboce output from linker
         QMAKE_LFLAGS +=  -Wl,--verbose
 
         # statically link with icu libraries in order to avoid version conflict
         QMAKE_LFLAGS += `pkg-config --libs-only-L icu-uc`
-        LIBS += -Wl,-Bstatic -licui18n -licuuc -licudata -Wl,-Bdynamic
+        LIBS += -Wl,-Bstatic -licui18n -licuuc -licudata -Wl,-Bdynamic -ldl
     }
     solaris-cc {
         QMAKE_LFLAGS += -M$$PWD/mapfile-vers
--- a/modules/web/src/main/native/Source/WebCore/css/MediaQueryMatcher.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/css/MediaQueryMatcher.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -28,6 +28,7 @@
 #include "MediaQueryEvaluator.h"
 #include "MediaQueryList.h"
 #include "MediaQueryListListener.h"
+#include "NodeRenderStyle.h"
 #include "StyleResolver.h"
 
 namespace WebCore {
@@ -84,7 +85,7 @@
     if (!documentElement)
         return nullptr;
 
-    RefPtr<RenderStyle> rootStyle = m_document->ensureStyleResolver().styleForElement(documentElement, 0 /*defaultParent*/, DisallowStyleSharing, MatchOnlyUserAgentRules);
+    RefPtr<RenderStyle> rootStyle = m_document->ensureStyleResolver().styleForElement(documentElement, m_document->renderStyle(), DisallowStyleSharing, MatchOnlyUserAgentRules);
 
     return std::make_unique<MediaQueryEvaluator>(mediaType(), m_document->frame(), rootStyle.get());
 }
--- a/modules/web/src/main/native/Source/WebCore/css/SVGCSSStyleSelector.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/css/SVGCSSStyleSelector.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -110,8 +110,8 @@
     const State& state = m_state;
     SVGRenderStyle& svgStyle = state.style()->accessSVGStyle();
 
-    bool isInherit = state.parentNode() && value->isInheritedValue();
-    bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue());
+    bool isInherit = state.parentStyle() && value->isInheritedValue();
+    bool isInitial = value->isInitialValue() || (!state.parentStyle() && value->isInheritedValue());
 
     // What follows is a list that maps the CSS properties into their
     // corresponding front-end RenderStyle values. Shorthands(e.g. border,
--- a/modules/web/src/main/native/Source/WebCore/css/StyleMedia.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/css/StyleMedia.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -31,6 +31,7 @@
 #include "FrameView.h"
 #include "MediaList.h"
 #include "MediaQueryEvaluator.h"
+#include "NodeRenderStyle.h"
 #include "StyleResolver.h"
 
 namespace WebCore {
@@ -60,7 +61,7 @@
     if (!documentElement)
         return false;
 
-    RefPtr<RenderStyle> rootStyle = document->ensureStyleResolver().styleForElement(documentElement, 0 /*defaultParent*/, DisallowStyleSharing, MatchOnlyUserAgentRules);
+    RefPtr<RenderStyle> rootStyle = document->ensureStyleResolver().styleForElement(documentElement, document->renderStyle(), DisallowStyleSharing, MatchOnlyUserAgentRules);
 
     RefPtr<MediaQuerySet> media = MediaQuerySet::create();
     if (!media->parse(query))
--- a/modules/web/src/main/native/Source/WebCore/css/StyleResolver.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/css/StyleResolver.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -88,7 +88,6 @@
 #include "MediaList.h"
 #include "MediaQueryEvaluator.h"
 #include "NodeRenderStyle.h"
-#include "NodeRenderingTraversal.h"
 #include "Page.h"
 #include "PageRuleCollector.h"
 #include "Pair.h"
@@ -233,7 +232,6 @@
     m_element = nullptr;
     m_styledElement = nullptr;
     m_parentStyle = nullptr;
-    m_parentNode = nullptr;
     m_regionForStyling = nullptr;
     m_pendingImageProperties.clear();
 #if ENABLE(CSS_FILTERS)
@@ -280,7 +278,7 @@
         m_medium = std::make_unique<MediaQueryEvaluator>("all");
 
     if (root)
-        m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules);
+        m_rootDefaultStyle = styleForElement(root, m_document.renderStyle(), DisallowStyleSharing, MatchOnlyUserAgentRules);
 
     if (m_rootDefaultStyle && view)
         m_medium = std::make_unique<MediaQueryEvaluator>(view->mediaType(), &view->frame(), m_rootDefaultStyle.get());
@@ -406,15 +404,10 @@
     m_regionForStyling = regionForStyling;
 
     if (e) {
-        m_parentNode = NodeRenderingTraversal::parent(e);
         bool resetStyleInheritance = hasShadowRootParent(*e) && toShadowRoot(e->parentNode())->resetStyleInheritance();
-        m_parentStyle = resetStyleInheritance ? 0 :
-            parentStyle ? parentStyle :
-            m_parentNode ? m_parentNode->renderStyle() : 0;
-    } else {
-        m_parentNode = 0;
+        m_parentStyle = resetStyleInheritance ? nullptr : parentStyle;
+    } else
         m_parentStyle = parentStyle;
-    }
 
     Node* docElement = e ? e->document().documentElement() : 0;
     RenderStyle* docStyle = document.renderStyle();
@@ -894,7 +887,7 @@
     for (unsigned i = 0; i < keyframes.size(); ++i) {
         // Apply the declaration to the style. This is a simplified version of the logic in styleForElement
         initElement(e);
-        m_state.initForStyleResolve(document(), e);
+        m_state.initForStyleResolve(document(), e, nullptr);
 
         const StyleKeyframe* keyframe = keyframes[i].get();
 
@@ -991,7 +984,7 @@
 
 PassRef<RenderStyle> StyleResolver::styleForPage(int pageIndex)
 {
-    m_state.initForStyleResolve(document(), document().documentElement()); // m_rootElementStyle will be set to the document style.
+    m_state.initForStyleResolve(m_document, m_document.documentElement(), m_document.renderStyle());
 
     m_state.setStyle(RenderStyle::create());
     m_state.style()->inheritFrom(m_state.rootElementStyle());
@@ -1753,7 +1746,7 @@
 void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, RenderStyle* style)
 {
     initElement(0);
-    m_state.initForStyleResolve(document(), 0, style);
+    m_state.initForStyleResolve(document(), nullptr, style);
     m_state.setStyle(*style);
     applyPropertyToCurrentStyle(id, value);
 }
@@ -2014,11 +2007,10 @@
         return applyProperty(newId, value);
     }
 
-    bool isInherit = state.parentNode() && value->isInheritedValue();
-    bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue());
+    bool isInherit = state.parentStyle() && value->isInheritedValue();
+    bool isInitial = value->isInitialValue() || (!state.parentStyle() && value->isInheritedValue());
 
     ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
-    ASSERT(!isInherit || (state.parentNode() && state.parentStyle())); // isInherit -> (state.parentNode() && state.parentStyle())
 
     if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) {
         // Limit the properties that can be applied to only the ones honored by :visited.
--- a/modules/web/src/main/native/Source/WebCore/css/StyleResolver.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/css/StyleResolver.h	Thu Mar 10 14:16:20 2016 -0800
@@ -143,8 +143,8 @@
     void pushParentElement(Element*);
     void popParentElement(Element*);
 
-    PassRef<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle = 0, StyleSharingBehavior = AllowStyleSharing,
-        RuleMatchingBehavior = MatchAllRules, RenderRegion* regionForStyling = 0);
+    PassRef<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle, StyleSharingBehavior = AllowStyleSharing,
+        RuleMatchingBehavior = MatchAllRules, RenderRegion* regionForStyling = nullptr);
 
     void keyframeStylesForAnimation(Element*, const RenderStyle*, KeyframeList&);
 
@@ -158,7 +158,6 @@
     RenderStyle* rootElementStyle() const { return m_state.rootElementStyle(); }
     Element* element() { return m_state.element(); }
     Document& document() { return m_document; }
-    bool hasParentNode() const { return m_state.parentNode(); }
 
     // FIXME: It could be better to call m_ruleSets.appendAuthorStyleSheets() directly after we factor StyleRsolver further.
     // https://bugs.webkit.org/show_bug.cgi?id=108890
@@ -333,7 +332,6 @@
         State()
         : m_element(0)
         , m_styledElement(0)
-        , m_parentNode(0)
         , m_parentStyle(0)
         , m_rootElementStyle(0)
         , m_regionForStyling(0)
@@ -348,7 +346,7 @@
 
     public:
         void initElement(Element*);
-        void initForStyleResolve(Document&, Element*, RenderStyle* parentStyle = 0, RenderRegion* regionForStyling = 0);
+        void initForStyleResolve(Document&, Element*, RenderStyle* parentStyle, RenderRegion* regionForStyling = nullptr);
         void clear();
 
         Document& document() const { return m_element->document(); }
@@ -358,7 +356,6 @@
         RenderStyle* style() const { return m_style.get(); }
         PassRef<RenderStyle> takeStyle() { return m_style.releaseNonNull(); }
 
-        const ContainerNode* parentNode() const { return m_parentNode; }
         void setParentStyle(PassRef<RenderStyle> parentStyle) { m_parentStyle = std::move(parentStyle); }
         RenderStyle* parentStyle() const { return m_parentStyle.get(); }
         RenderStyle* rootElementStyle() const { return m_rootElementStyle; }
@@ -405,7 +402,6 @@
         Element* m_element;
         RefPtr<RenderStyle> m_style;
         StyledElement* m_styledElement;
-        ContainerNode* m_parentNode;
         RefPtr<RenderStyle> m_parentStyle;
         RenderStyle* m_rootElementStyle;
 
--- a/modules/web/src/main/native/Source/WebCore/dom/Element.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/Element.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -1434,16 +1434,6 @@
         document().renderView()->flowThreadController().unregisterNamedFlowContentElement(*this);
 }
 
-PassRef<RenderStyle> Element::styleForRenderer()
-{
-    if (hasCustomStyleResolveCallbacks()) {
-        if (RefPtr<RenderStyle> style = customStyleForRenderer())
-            return style.releaseNonNull();
-    }
-
-    return document().ensureStyleResolver().styleForElement(this);
-}
-
 ShadowRoot* Element::shadowRoot() const
 {
     return hasRareData() ? elementRareData()->shadowRoot() : 0;
@@ -1458,8 +1448,6 @@
 {
     if (element.isShadowRoot())
         return true;
-    if (element.isPseudoElement() || element.beforePseudoElement() || element.afterPseudoElement())
-        return true;
     return element.isInsertionPoint() || element.shadowRoot();
 }
 
@@ -2298,13 +2286,11 @@
 void Element::setBeforePseudoElement(PassRefPtr<PseudoElement> element)
 {
     ensureElementRareData().setBeforePseudoElement(element);
-    resetNeedsNodeRenderingTraversalSlowPath();
 }
 
 void Element::setAfterPseudoElement(PassRefPtr<PseudoElement> element)
 {
     ensureElementRareData().setAfterPseudoElement(element);
-    resetNeedsNodeRenderingTraversalSlowPath();
 }
 
 static void disconnectPseudoElement(PseudoElement* pseudoElement)
@@ -2323,7 +2309,6 @@
         return;
     disconnectPseudoElement(elementRareData()->beforePseudoElement());
     elementRareData()->setBeforePseudoElement(nullptr);
-    resetNeedsNodeRenderingTraversalSlowPath();
 }
 
 void Element::clearAfterPseudoElement()
@@ -2332,7 +2317,6 @@
         return;
     disconnectPseudoElement(elementRareData()->afterPseudoElement());
     elementRareData()->setAfterPseudoElement(nullptr);
-    resetNeedsNodeRenderingTraversalSlowPath();
 }
 
 // ElementTraversal API
@@ -2953,7 +2937,7 @@
     ASSERT(hasCustomStyleResolveCallbacks());
 }
 
-PassRefPtr<RenderStyle> Element::customStyleForRenderer()
+PassRefPtr<RenderStyle> Element::customStyleForRenderer(RenderStyle&)
 {
     ASSERT(hasCustomStyleResolveCallbacks());
     return 0;
--- a/modules/web/src/main/native/Source/WebCore/dom/Element.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/Element.h	Thu Mar 10 14:16:20 2016 -0800
@@ -524,8 +524,6 @@
 
     virtual bool isSpellCheckingEnabled() const;
 
-    PassRef<RenderStyle> styleForRenderer();
-
     RenderRegion* renderRegion() const;
 
 #if ENABLE(CSS_REGIONS)
@@ -558,6 +556,7 @@
     virtual void didAttachRenderers();
     virtual void willDetachRenderers();
     virtual void didDetachRenderers();
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle);
 
     void setBeforePseudoElement(PassRefPtr<PseudoElement>);
     void setAfterPseudoElement(PassRefPtr<PseudoElement>);
@@ -579,8 +578,6 @@
     virtual void childrenChanged(const ChildChange&) override;
     virtual void removeAllEventListeners() override final;
 
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer();
-
     void clearTabIndexExplicitlyIfNeeded();
     void setTabIndexExplicitly(short);
 
--- a/modules/web/src/main/native/Source/WebCore/dom/NodeRenderStyle.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/NodeRenderStyle.h	Thu Mar 10 14:16:20 2016 -0800
@@ -25,6 +25,7 @@
 #ifndef NodeRenderStyle_h
 #define NodeRenderStyle_h
 
+#include "RenderElement.h"
 #include "RenderObject.h"
 #include "RenderStyle.h"
 #include "Node.h"
--- a/modules/web/src/main/native/Source/WebCore/dom/NodeRenderingTraversal.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/NodeRenderingTraversal.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -29,7 +29,6 @@
 #include "NodeRenderingTraversal.h"
 
 #include "InsertionPoint.h"
-#include "PseudoElement.h"
 #include "ShadowRoot.h"
 
 namespace WebCore {
@@ -121,9 +120,6 @@
 
 static ContainerNode* traverseParent(const Node* node, ShadowRootCrossing shadowRootCrossing)
 {
-    if (node->isPseudoElement())
-        return toPseudoElement(node)->hostElement();
-
     if (shadowRootCrossing == DontCrossShadowRoot  && node->isShadowRoot())
         return 0;
 
@@ -222,47 +218,25 @@
     return traverseParent(node, CrossShadowRoot);
 }
 
+Node* firstChildSlow(const Node* node)
+{
+    ASSERT(!node->isShadowRoot());
+
+    return traverseFirstChild(node, DontCrossShadowRoot);
+}
+
 Node* nextSiblingSlow(const Node* node)
 {
     ASSERT(!node->isShadowRoot());
 
-    // FIXME: Why do these functions deal with before/after when other code here doesn't?
-    Node* nextSibling = 0;
-    if (node->isBeforePseudoElement()) {
-        nextSibling = traverseParent(node, CrossShadowRoot);
-        nextSibling = traverseFirstChild(nextSibling, CrossShadowRoot);
-    } else
-        nextSibling = traverseNextSibling(node);
-
-    if (nextSibling || node->isAfterPseudoElement())
-        return nextSibling;
-
-    Node* parent = traverseParent(node, CrossShadowRoot);
-    if (parent && parent->isElementNode())
-        return toElement(parent)->afterPseudoElement();
-
-    return 0;
+    return traverseNextSibling(node);
 }
 
 Node* previousSiblingSlow(const Node* node)
 {
     ASSERT(!node->isShadowRoot());
 
-    Node* previousSibling = 0;
-    if (node->isAfterPseudoElement()) {
-        ContainerNode* parent = traverseParent(node, CrossShadowRoot);
-        previousSibling = traverseLastChild(parent, CrossShadowRoot);
-    } else
-        previousSibling = traversePreviousSibling(node);
-
-    if (previousSibling || node->isBeforePseudoElement())
-        return previousSibling;
-
-    ContainerNode* parent = traverseParent(node, CrossShadowRoot);
-    if (parent && parent->isElementNode())
-        return toElement(parent)->beforePseudoElement();
-
-    return 0;
+    return traversePreviousSibling(node);
 }
 
 Node* nextInScope(const Node* node)
--- a/modules/web/src/main/native/Source/WebCore/dom/NodeRenderingTraversal.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/NodeRenderingTraversal.h	Thu Mar 10 14:16:20 2016 -0800
@@ -35,6 +35,7 @@
 namespace NodeRenderingTraversal {
 
 ContainerNode* parent(const Node*);
+Node* firstChild(const Node*);
 Node* nextSibling(const Node*);
 Node* previousSibling(const Node*);
 
@@ -44,11 +45,13 @@
 Node* lastChildInScope(const Node*);
 
 ContainerNode* parentSlow(const Node*);
+Node* firstChildSlow(const Node*);
 Node* nextSiblingSlow(const Node*);
 Node* previousSiblingSlow(const Node*);
 
 inline ContainerNode* parent(const Node* node)
 {
+    ASSERT(!node->isPseudoElement());
     if (node->needsNodeRenderingTraversalSlowPath())
         return parentSlow(node);
 
@@ -56,8 +59,19 @@
     return node->parentNodeGuaranteedHostFree();
 }
 
+inline Node* firstChild(const Node* node)
+{
+    ASSERT(!node->isPseudoElement());
+    if (node->needsNodeRenderingTraversalSlowPath())
+        return firstChildSlow(node);
+
+    ASSERT(nextSiblingSlow(node) == node->nextSibling());
+    return node->firstChild();
+}
+
 inline Node* nextSibling(const Node* node)
 {
+    ASSERT(!node->isPseudoElement());
     if (node->needsNodeRenderingTraversalSlowPath())
         return nextSiblingSlow(node);
 
@@ -67,6 +81,7 @@
 
 inline Node* previousSibling(const Node* node)
 {
+    ASSERT(!node->isPseudoElement());
     if (node->needsNodeRenderingTraversalSlowPath())
         return previousSiblingSlow(node);
 
--- a/modules/web/src/main/native/Source/WebCore/dom/PseudoElement.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/PseudoElement.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -70,9 +70,9 @@
     InspectorInstrumentation::pseudoElementDestroyed(document().page(), this);
 }
 
-PassRefPtr<RenderStyle> PseudoElement::customStyleForRenderer()
+PassRefPtr<RenderStyle> PseudoElement::customStyleForRenderer(RenderStyle& parentStyle)
 {
-    return m_hostElement->renderer()->getCachedPseudoStyle(m_pseudoId);
+    return m_hostElement->renderer()->getCachedPseudoStyle(m_pseudoId, &parentStyle);
 }
 
 void PseudoElement::didAttachRenderers()
--- a/modules/web/src/main/native/Source/WebCore/dom/PseudoElement.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/dom/PseudoElement.h	Thu Mar 10 14:16:20 2016 -0800
@@ -45,7 +45,7 @@
     Element* hostElement() const { return m_hostElement; }
     void clearHostElement() { m_hostElement = nullptr; }
 
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
     virtual void didAttachRenderers() override;
     virtual bool rendererIsNeeded(const RenderStyle&) override;
 
--- a/modules/web/src/main/native/Source/WebCore/html/HTMLOptGroupElement.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/HTMLOptGroupElement.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -96,7 +96,7 @@
     // manually cache the value. This happens if our parent doesn't have a
     // renderer like <optgroup> or if it doesn't allow children like <select>.
     if (!m_style && parentNode()->renderStyle())
-        updateNonRenderStyle();
+        updateNonRenderStyle(*parentNode()->renderStyle());
 }
 
 void HTMLOptGroupElement::willDetachRenderers()
@@ -104,9 +104,9 @@
     m_style.clear();
 }
 
-void HTMLOptGroupElement::updateNonRenderStyle()
+void HTMLOptGroupElement::updateNonRenderStyle(RenderStyle& parentStyle)
 {
-    m_style = document().ensureStyleResolver().styleForElement(this);
+    m_style = document().ensureStyleResolver().styleForElement(this, &parentStyle);
 }
 
 RenderStyle* HTMLOptGroupElement::nonRendererStyle() const
@@ -114,11 +114,11 @@
     return m_style.get();
 }
 
-PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer()
+PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer(RenderStyle& parentStyle)
 {
     // styleForRenderer is called whenever a new style should be associated
     // with an Element so now is a good time to update our cached style.
-    updateNonRenderStyle();
+    updateNonRenderStyle(parentStyle);
     return m_style;
 }
 
--- a/modules/web/src/main/native/Source/WebCore/html/HTMLOptGroupElement.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/HTMLOptGroupElement.h	Thu Mar 10 14:16:20 2016 -0800
@@ -54,9 +54,9 @@
     virtual void accessKeyAction(bool sendMouseEvents) override;
 
     // <optgroup> never has a renderer so we manually manage a cached style.
-    void updateNonRenderStyle();
+    void updateNonRenderStyle(RenderStyle& parentStyle);
     virtual RenderStyle* nonRendererStyle() const override;
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
 
     void recalcSelectOptions();
 
--- a/modules/web/src/main/native/Source/WebCore/html/HTMLOptionElement.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/HTMLOptionElement.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -94,7 +94,7 @@
     // manually cache the value. This happens if our parent doesn't have a
     // renderer like <optgroup> or if it doesn't allow children like <select>.
     if (!m_style && parentNode()->renderStyle())
-        updateNonRenderStyle();
+        updateNonRenderStyle(*parentNode()->renderStyle());
 }
 
 void HTMLOptionElement::willDetachRenderers()
@@ -300,9 +300,9 @@
     setAttribute(labelAttr, label);
 }
 
-void HTMLOptionElement::updateNonRenderStyle()
+void HTMLOptionElement::updateNonRenderStyle(RenderStyle& parentStyle)
 {
-    m_style = document().ensureStyleResolver().styleForElement(this);
+    m_style = document().ensureStyleResolver().styleForElement(this, &parentStyle);
 }
 
 RenderStyle* HTMLOptionElement::nonRendererStyle() const
@@ -310,11 +310,11 @@
     return m_style.get();
 }
 
-PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer()
+PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer(RenderStyle& parentStyle)
 {
     // styleForRenderer is called whenever a new style should be associated
     // with an Element so now is a good time to update our cached style.
-    updateNonRenderStyle();
+    updateNonRenderStyle(parentStyle);
     return m_style;
 }
 
--- a/modules/web/src/main/native/Source/WebCore/html/HTMLOptionElement.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/HTMLOptionElement.h	Thu Mar 10 14:16:20 2016 -0800
@@ -82,9 +82,9 @@
     virtual void childrenChanged(const ChildChange&) override;
 
     // <option> never has a renderer so we manually manage a cached style.
-    void updateNonRenderStyle();
+    void updateNonRenderStyle(RenderStyle& parentStyle);
     virtual RenderStyle* nonRendererStyle() const override;
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
 
     virtual void didRecalcStyle(Style::Change) override;
 
--- a/modules/web/src/main/native/Source/WebCore/html/HTMLTitleElement.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/HTMLTitleElement.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -25,8 +25,10 @@
 
 #include "Document.h"
 #include "HTMLNames.h"
+#include "NodeRenderStyle.h"
 #include "RenderStyle.h"
 #include "StyleInheritedData.h"
+#include "StyleResolver.h"
 #include "Text.h"
 #include "TextNodeTraversal.h"
 #include <wtf/Ref.h>
@@ -85,7 +87,7 @@
     if (RenderStyle* computedStyle = this->computedStyle())
         direction = computedStyle->direction();
     else {
-        Ref<RenderStyle> style(styleForRenderer());
+        Ref<RenderStyle> style(document().ensureStyleResolver().styleForElement(this, parentElement() ? parentElement()->renderStyle() : nullptr));
         direction = style.get().direction();
     }
     return StringWithDirection(text(), direction);
--- a/modules/web/src/main/native/Source/WebCore/html/shadow/TextControlInnerElements.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/shadow/TextControlInnerElements.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -74,7 +74,7 @@
     return adoptRef(new TextControlInnerElement(document));
 }
 
-PassRefPtr<RenderStyle> TextControlInnerElement::customStyleForRenderer()
+PassRefPtr<RenderStyle> TextControlInnerElement::customStyleForRenderer(RenderStyle&)
 {
     RenderTextControlSingleLine* parentRenderer = toRenderTextControlSingleLine(shadowHost()->renderer());
     return parentRenderer->createInnerBlockStyle(&parentRenderer->style());
@@ -122,7 +122,7 @@
     return toRenderTextControlInnerBlock(HTMLDivElement::renderer());
 }
 
-PassRefPtr<RenderStyle> TextControlInnerTextElement::customStyleForRenderer()
+PassRefPtr<RenderStyle> TextControlInnerTextElement::customStyleForRenderer(RenderStyle&)
 {
     RenderTextControl* parentRenderer = toRenderTextControl(shadowHost()->renderer());
     return parentRenderer->createInnerTextStyle(&parentRenderer->style());
--- a/modules/web/src/main/native/Source/WebCore/html/shadow/TextControlInnerElements.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/html/shadow/TextControlInnerElements.h	Thu Mar 10 14:16:20 2016 -0800
@@ -50,7 +50,7 @@
 
 protected:
     TextControlInnerElement(Document&);
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
 
 private:
     virtual bool isMouseFocusable() const override { return false; }
@@ -67,7 +67,7 @@
 private:
     TextControlInnerTextElement(Document&);
     virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
     virtual bool isMouseFocusable() const override { return false; }
     virtual bool isTextControlInnerTextElement() const override { return true; }
 };
--- a/modules/web/src/main/native/Source/WebCore/rendering/RenderNamedFlowFragment.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/rendering/RenderNamedFlowFragment.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -34,6 +34,7 @@
 #include "PaintInfo.h"
 #include "RenderBoxRegionInfo.h"
 #include "RenderFlowThread.h"
+#include "RenderIterator.h"
 #include "RenderNamedFlowThread.h"
 #include "RenderView.h"
 #include "StyleResolver.h"
@@ -278,24 +279,21 @@
     toRenderNamedFlowThread(m_flowThread)->checkRegionsWithStyling();
 }
 
-PassRefPtr<RenderStyle> RenderNamedFlowFragment::computeStyleInRegion(const RenderObject* object)
+PassRefPtr<RenderStyle> RenderNamedFlowFragment::computeStyleInRegion(RenderElement& renderer, RenderStyle& parentStyle)
 {
-    ASSERT(object);
-    ASSERT(!object->isAnonymous());
-    ASSERT(object->node() && object->node()->isElementNode());
+    ASSERT(!renderer.isAnonymous());
 
     // FIXME: Region styling fails for pseudo-elements because the renderers don't have a node.
-    Element* element = toElement(object->node());
-    RefPtr<RenderStyle> renderObjectRegionStyle = object->view().document().ensureStyleResolver().styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this);
+    RefPtr<RenderStyle> renderObjectRegionStyle = renderer.view().document().ensureStyleResolver().styleForElement(renderer.element(), &parentStyle, DisallowStyleSharing, MatchAllRules, this);
 
     return renderObjectRegionStyle.release();
 }
 
-void RenderNamedFlowFragment::computeChildrenStyleInRegion(const RenderElement* object)
+void RenderNamedFlowFragment::computeChildrenStyleInRegion(RenderElement& renderer)
 {
-    for (RenderObject* child = object->firstChild(); child; child = child->nextSibling()) {
+    for (auto& child : childrenOfType<RenderObject>(renderer)) {
 
-        auto it = m_renderObjectRegionStyle.find(child);
+        auto it = m_renderObjectRegionStyle.find(&child);
 
         RefPtr<RenderStyle> childStyleInRegion;
         bool objectRegionStyleCached = false;
@@ -303,17 +301,17 @@
             childStyleInRegion = it->value.style;
             objectRegionStyleCached = true;
         } else {
-            if (child->isAnonymous() || child->isInFlowRenderFlowThread())
-                childStyleInRegion = RenderStyle::createAnonymousStyleWithDisplay(&object->style(), child->style().display());
-            else if (child->isText())
-                childStyleInRegion = RenderStyle::clone(&object->style());
+            if (child.isAnonymous() || child.isInFlowRenderFlowThread())
+                childStyleInRegion = RenderStyle::createAnonymousStyleWithDisplay(&renderer.style(), child.style().display());
+            else if (child.isText())
+                childStyleInRegion = RenderStyle::clone(&renderer.style());
             else
-                childStyleInRegion = computeStyleInRegion(child);
+                childStyleInRegion = computeStyleInRegion(toRenderElement(child), renderer.style());
         }
 
-        setObjectStyleInRegion(child, childStyleInRegion, objectRegionStyleCached);
+        setObjectStyleInRegion(&child, childStyleInRegion, objectRegionStyleCached);
 
-        if (child->isRenderElement())
+        if (child.isRenderElement())
             computeChildrenStyleInRegion(toRenderElement(child));
     }
 }
@@ -381,11 +379,11 @@
             ASSERT(it->value.cached);
             objectRegionStyleCached = true;
         } else
-            objectStyleInRegion = computeStyleInRegion(object);
+            objectStyleInRegion = computeStyleInRegion(*object, style());
 
         setObjectStyleInRegion(object, objectStyleInRegion, objectRegionStyleCached);
 
-        computeChildrenStyleInRegion(object);
+        computeChildrenStyleInRegion(*object);
     }
 }
 
--- a/modules/web/src/main/native/Source/WebCore/rendering/RenderNamedFlowFragment.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/rendering/RenderNamedFlowFragment.h	Thu Mar 10 14:16:20 2016 -0800
@@ -114,8 +114,8 @@
 private:
     virtual const char* renderName() const override { return "RenderNamedFlowFragment"; }
 
-    PassRefPtr<RenderStyle> computeStyleInRegion(const RenderObject*);
-    void computeChildrenStyleInRegion(const RenderElement*);
+    PassRefPtr<RenderStyle> computeStyleInRegion(RenderElement&, RenderStyle& parentStyle);
+    void computeChildrenStyleInRegion(RenderElement&);
     void setObjectStyleInRegion(RenderObject*, PassRefPtr<RenderStyle>, bool objectRegionStyleCached);
 
     void updateRegionHasAutoLogicalHeightFlag();
--- a/modules/web/src/main/native/Source/WebCore/style/StyleResolveTree.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/style/StyleResolveTree.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -4,7 +4,7 @@
  *           (C) 2001 Peter Kelly (pmk@post.com)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2010, 2012-2014 Apple Inc. All rights reserved.
  *           (C) 2007 Eric Seidel (eric@webkit.org)
  *
  * This library is free software; you can redistribute it and/or
@@ -60,10 +60,34 @@
 
 enum DetachType { NormalDetach, ReattachDetach };
 
-static void attachRenderTree(Element&, PassRefPtr<RenderStyle>);
-static void attachTextRenderer(Text&);
+class RenderTreePosition {
+public:
+    RenderTreePosition(RenderElement* parent);
+    RenderTreePosition(RenderElement* parent, RenderObject* nextSibling);
+
+    RenderElement* parent() { return m_parent; }
+
+    void insert(RenderObject&);
+    bool canInsert(RenderElement&) const;
+    bool canInsert(RenderText&) const;
+
+    void computeNextSibling(const Node&, ContainerNode& renderingParentNode);
+    void invalidateNextSibling(const RenderObject&);
+
+private:
+    RenderElement* m_parent;
+    RenderObject* m_nextSibling;
+    bool m_hasValidNextSibling;
+#if !ASSERT_DISABLED
+    unsigned m_assertionLimitCounter;
+#endif
+};
+
+static void attachRenderTree(Element&, ContainerNode& renderingParentNode, RenderTreePosition&, PassRefPtr<RenderStyle>);
+static void attachTextRenderer(Text&, ContainerNode& renderingParentNode, RenderTreePosition&);
 static void detachRenderTree(Element&, DetachType);
-static void resolveTree(Element&, Change);
+static void resolveTextNode(Text&, ContainerNode& renderingParentNode, RenderTreePosition&);
+static void resolveTree(Element&, ContainerNode& renderingParentNode, RenderTreePosition&, Change);
 
 Change determineChange(const RenderStyle* s1, const RenderStyle* s2)
 {
@@ -126,43 +150,120 @@
     return false;
 }
 
-static RenderObject* nextSiblingRenderer(const Element& element, const ContainerNode* renderingParentNode)
+static RenderObject* nextSiblingRenderer(const Node& node, const ContainerNode& renderingParentNode)
 {
+    if (!renderingParentNode.isElementNode())
+        return nullptr;
+    const Element& renderingParentElement = toElement(renderingParentNode);
     // Avoid an O(N^2) problem with this function by not checking for
     // nextRenderer() when the parent element hasn't attached yet.
     // FIXME: Why would we get here anyway if parent is not attached?
-    if (renderingParentNode && !renderingParentNode->renderer())
+    if (!renderingParentElement.renderer())
         return nullptr;
-    for (Node* sibling = NodeRenderingTraversal::nextSibling(&element); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
+    if (node.isAfterPseudoElement())
+        return nullptr;
+    Node* sibling = node.isBeforePseudoElement() ? NodeRenderingTraversal::firstChild(&renderingParentNode) : NodeRenderingTraversal::nextSibling(&node);
+    for (; sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
         RenderObject* renderer = sibling->renderer();
         if (renderer && !isRendererReparented(renderer))
             return renderer;
     }
+    if (PseudoElement* after = renderingParentElement.afterPseudoElement())
+        return after->renderer();
     return nullptr;
 }
 
-static bool shouldCreateRenderer(const Element& element, const ContainerNode* renderingParent)
+RenderTreePosition::RenderTreePosition(RenderElement* parent)
+    : m_parent(parent)
+    , m_nextSibling(nullptr)
+    , m_hasValidNextSibling(false)
+#if !ASSERT_DISABLED
+    , m_assertionLimitCounter(0)
+#endif
+{
+}
+
+RenderTreePosition::RenderTreePosition(RenderElement* parent, RenderObject* nextSibling)
+    : m_parent(parent)
+    , m_nextSibling(nextSibling)
+    , m_hasValidNextSibling(true)
+#if !ASSERT_DISABLED
+    , m_assertionLimitCounter(0)
+#endif
+{
+}
+
+bool RenderTreePosition::canInsert(RenderElement& renderer) const
+{
+    ASSERT(m_parent);
+    ASSERT(!renderer.parent());
+    return m_parent->isChildAllowed(renderer, renderer.style());
+}
+
+bool RenderTreePosition::canInsert(RenderText& renderer) const
+{
+    ASSERT(m_parent);
+    ASSERT(!renderer.parent());
+    return m_parent->isChildAllowed(renderer, m_parent->style());
+}
+
+void RenderTreePosition::insert(RenderObject& renderer)
+{
+    ASSERT(m_parent);
+    ASSERT(m_hasValidNextSibling);
+    m_parent->addChild(&renderer, m_nextSibling);
+}
+
+void RenderTreePosition::computeNextSibling(const Node& node, ContainerNode& renderingParentNode)
+{
+    ASSERT(!node.renderer());
+    if (m_hasValidNextSibling) {
+        // Stop validating at some point so the assert doesn't make us O(N^2) on debug builds.
+        ASSERT(++m_assertionLimitCounter > 20 || nextSiblingRenderer(node, renderingParentNode) == m_nextSibling);
+        return;
+    }
+    m_nextSibling = nextSiblingRenderer(node, renderingParentNode);
+    m_hasValidNextSibling = true;
+}
+
+void RenderTreePosition::invalidateNextSibling(const RenderObject& siblingRenderer)
+{
+    if (!m_hasValidNextSibling)
+        return;
+    if (m_nextSibling == &siblingRenderer)
+        m_hasValidNextSibling = false;
+}
+
+static bool shouldCreateRenderer(const Element& element, const ContainerNode& renderingParent)
 {
     if (!element.document().shouldCreateRenderers())
         return false;
-    if (!renderingParent)
-        return false;
-    RenderObject* parentRenderer = renderingParent->renderer();
+    RenderObject* parentRenderer = renderingParent.renderer();
     if (!parentRenderer)
         return false;
     if (!parentRenderer->canHaveChildren() && !(element.isPseudoElement() && parentRenderer->canHaveGeneratedChildren()))
         return false;
-    if (!renderingParent->childShouldCreateRenderer(element))
+    if (!renderingParent.childShouldCreateRenderer(element))
         return false;
     return true;
 }
 
+static PassRef<RenderStyle> styleForElement(Element& element, ContainerNode& renderingParentNode)
+{
+    RenderStyle* parentStyle = renderingParentNode.renderStyle();
+    if (element.hasCustomStyleResolveCallbacks() && parentStyle) {
+        if (RefPtr<RenderStyle> style = element.customStyleForRenderer(*parentStyle))
+            return style.releaseNonNull();
+    }
+    return element.document().ensureStyleResolver().styleForElement(&element, parentStyle);
+}
+
 // Check the specific case of elements that are children of regions but are flowed into a flow thread themselves.
-static bool elementInsideRegionNeedsRenderer(Element& element, const ContainerNode* renderingParentNode, RefPtr<RenderStyle>& style)
+static bool elementInsideRegionNeedsRenderer(Element& element, ContainerNode& renderingParentNode, RefPtr<RenderStyle>& style)
 {
 #if ENABLE(CSS_REGIONS)
     // The parent of a region should always be an element.
-    const RenderElement* parentRenderer = renderingParentNode ? renderingParentNode->renderer() : 0;
+    const RenderElement* parentRenderer = renderingParentNode.renderer();
 
     bool parentIsRegion = parentRenderer && !parentRenderer->canHaveChildren() && parentRenderer->isRenderNamedFlowFragmentContainer();
     bool parentIsNonRenderedInsideRegion = !parentRenderer && element.parentElement() && element.parentElement()->isInsideRegion();
@@ -170,7 +271,7 @@
         return false;
 
     if (!style)
-        style = element.styleForRenderer();
+        style = styleForElement(element, renderingParentNode);
 
     // Children of this element will only be allowed to be flowed into other flow-threads if display is NOT none.
     if (element.rendererIsNeeded(*style))
@@ -198,12 +299,10 @@
 }
 #endif
 
-static void createRendererIfNeeded(Element& element, PassRefPtr<RenderStyle> resolvedStyle)
+static void createRendererIfNeeded(Element& element, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle)
 {
     ASSERT(!element.renderer());
 
-    ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&element);
-
     RefPtr<RenderStyle> style = resolvedStyle;
 
     element.setIsInsideRegion(false);
@@ -212,7 +311,7 @@
         return;
 
     if (!style)
-        style = element.styleForRenderer();
+        style = styleForElement(element, renderingParentNode);
 
     RenderNamedFlowThread* parentFlowRenderer = 0;
 #if ENABLE(CSS_REGIONS)
@@ -222,28 +321,23 @@
     if (!element.rendererIsNeeded(*style))
         return;
 
-    RenderElement* parentRenderer;
-    RenderObject* nextRenderer;
-    if (parentFlowRenderer) {
-        parentRenderer = parentFlowRenderer;
-        nextRenderer = parentFlowRenderer->nextRendererForElement(element);
-    } else {
-        // FIXME: Make this path Element only, handle the root special case separately.
-        parentRenderer = renderingParentNode->renderer();
-        nextRenderer = nextSiblingRenderer(element, renderingParentNode);
-    }
+    renderTreePosition.computeNextSibling(element, renderingParentNode);
+
+    RenderTreePosition insertionPosition = parentFlowRenderer
+        ? RenderTreePosition(parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
+        : renderTreePosition;
 
     RenderElement* newRenderer = element.createElementRenderer(style.releaseNonNull()).leakPtr();
     if (!newRenderer)
         return;
-    if (!parentRenderer->isChildAllowed(*newRenderer, newRenderer->style())) {
+    if (!insertionPosition.canInsert(*newRenderer)) {
         newRenderer->destroy();
         return;
     }
 
     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
-    newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
+    newRenderer->setFlowThreadState(insertionPosition.parent()->flowThreadState());
 
     // Code below updateAnimations() can depend on Element::renderer() already being set.
     element.setRenderer(newRenderer);
@@ -257,13 +351,13 @@
 #if ENABLE(FULLSCREEN_API)
     Document& document = element.document();
     if (document.webkitIsFullScreen() && document.webkitCurrentFullScreenElement() == &element) {
-        newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, document);
+        newRenderer = RenderFullScreen::wrapRenderer(newRenderer, insertionPosition.parent(), document);
         if (!newRenderer)
             return;
     }
 #endif
     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
-    parentRenderer->addChild(newRenderer, nextRenderer);
+    insertionPosition.insert(*newRenderer);
 }
 
 static RenderObject* previousSiblingRenderer(const Text& textNode)
@@ -275,30 +369,19 @@
         if (renderer && !isRendererReparented(renderer))
             return renderer;
     }
-    return 0;
+    if (PseudoElement* before = textNode.parentElement()->beforePseudoElement())
+        return before->renderer();
+    return nullptr;
 }
 
-static RenderObject* nextSiblingRenderer(const Text& textNode)
-{
-    if (textNode.renderer())
-        return textNode.renderer()->nextSibling();
-    for (Node* sibling = NodeRenderingTraversal::nextSibling(&textNode); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
-        RenderObject* renderer = sibling->renderer();
-        if (renderer && !isRendererReparented(renderer))
-            return renderer;
-    }
-    return 0;
-}
-
-static void reattachTextRenderersForWhitespaceOnlySiblingsAfterAttachIfNeeded(Node& current)
+static void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
 {
     if (isInsertionPoint(current))
         return;
     // This function finds sibling text renderers where the results of textRendererIsNeeded may have changed as a result of
     // the current node gaining or losing the renderer. This can only affect white space text nodes.
-    for (Node* sibling = NodeRenderingTraversal::nextSibling(&current); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
-        // Siblings haven't been attached yet. They will be handled normally when they are.
-        if (sibling->styleChangeType() == ReconstructRenderTree)
+    for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
+        if (sibling->needsStyleRecalc())
             return;
         if (sibling->isElementNode()) {
             // Text renderers beyond rendered elements can't be affected.
@@ -308,33 +391,35 @@
         }
         if (!sibling->isTextNode())
             continue;
-        Text& textSibling = *toText(sibling);
-        if (!textSibling.length() || !textSibling.containsOnlyWhitespace())
-            return;
-        Text& whitespaceTextSibling = textSibling;
-        bool hadRenderer = whitespaceTextSibling.renderer();
-        detachTextRenderer(whitespaceTextSibling);
-        attachTextRenderer(whitespaceTextSibling);
-        // No changes, futher renderers can't be affected.
-        if (hadRenderer == !!whitespaceTextSibling.renderer())
-            return;
+        Text& textSibling = toText(*sibling);
+        if (!textSibling.containsOnlyWhitespace())
+            continue;
+        textSibling.setNeedsStyleRecalc();
     }
 }
 
-static bool textRendererIsNeeded(const Text& textNode, const RenderObject& parentRenderer, const RenderStyle& style)
+static bool textRendererIsNeeded(const Text& textNode, ContainerNode& renderingParentNode)
 {
+    if (!renderingParentNode.renderer())
+        return false;
+    RenderElement& parentRenderer = *renderingParentNode.renderer();
+    if (!parentRenderer.canHaveChildren())
+        return false;
+    if (!renderingParentNode.childShouldCreateRenderer(textNode))
+        return false;
+
     if (textNode.isEditingText())
         return true;
     if (!textNode.length())
         return false;
-    if (style.display() == NONE)
+    if (parentRenderer.style().display() == NONE)
         return false;
     if (!textNode.containsOnlyWhitespace())
         return true;
     // This text node has nothing but white space. We may still need a renderer in some cases.
     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
         return false;
-    if (style.preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
+    if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
         return true;
 
     RenderObject* previousRenderer = previousSiblingRenderer(textNode);
@@ -349,10 +434,10 @@
         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
             return false;
 
-        RenderObject* first = toRenderElement(parentRenderer).firstChild();
+        RenderObject* first = parentRenderer.firstChild();
         while (first && first->isFloatingOrOutOfFlowPositioned())
             first = first->nextSibling();
-        RenderObject* nextRenderer = nextSiblingRenderer(textNode);
+        RenderObject* nextRenderer = nextSiblingRenderer(textNode, *textNode.parentNode());
         if (!first || nextRenderer == first) {
             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
             return false;
@@ -361,43 +446,33 @@
     return true;
 }
 
-static void createTextRendererIfNeeded(Text& textNode)
+static void createTextRendererIfNeeded(Text& textNode, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition)
 {
     ASSERT(!textNode.renderer());
 
-    ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&textNode);
-    if (!renderingParentNode)
-        return;
-    RenderElement* parentRenderer = renderingParentNode->renderer();
-    if (!parentRenderer || !parentRenderer->canHaveChildren())
-        return;
-    if (!renderingParentNode->childShouldCreateRenderer(textNode))
+    if (!textRendererIsNeeded(textNode, renderingParentNode))
         return;
 
-    const auto& style = parentRenderer->style();
-
-    if (!textRendererIsNeeded(textNode, *parentRenderer, style))
-        return;
-
-    auto newRenderer = textNode.createTextRenderer(style);
+    auto newRenderer = textNode.createTextRenderer(*renderingParentNode.renderStyle());
     ASSERT(newRenderer);
 
-    if (!parentRenderer->isChildAllowed(*newRenderer, style))
+    renderTreePosition.computeNextSibling(textNode, renderingParentNode);
+
+    if (!renderTreePosition.canInsert(*newRenderer))
         return;
 
     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
-    newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
+    newRenderer->setFlowThreadState(renderTreePosition.parent()->flowThreadState());
 
-    RenderObject* nextRenderer = nextSiblingRenderer(textNode);
     textNode.setRenderer(newRenderer.get());
     // Parent takes care of the animations, no need to call setAnimatableStyle.
-    parentRenderer->addChild(newRenderer.leakPtr(), nextRenderer);
+    renderTreePosition.insert(*newRenderer.leakPtr());
 }
 
-void attachTextRenderer(Text& textNode)
+void attachTextRenderer(Text& textNode, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition)
 {
-    createTextRendererIfNeeded(textNode);
+    createTextRendererIfNeeded(textNode, renderingParentNode, renderTreePosition);
 
     textNode.clearNeedsStyleRecalc();
 }
@@ -411,62 +486,68 @@
 
 void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
 {
-    RenderText* textRenderer = textNode.renderer();
-    if (!textRenderer) {
-        attachTextRenderer(textNode);
-        reattachTextRenderersForWhitespaceOnlySiblingsAfterAttachIfNeeded(textNode);
+    ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&textNode);
+    if (!renderingParentNode)
         return;
-    }
-    RenderObject* parentRenderer = NodeRenderingTraversal::parent(&textNode)->renderer();
-    if (!textRendererIsNeeded(textNode, *parentRenderer, textRenderer->style())) {
-        detachTextRenderer(textNode);
-        attachTextRenderer(textNode);
-        reattachTextRenderersForWhitespaceOnlySiblingsAfterAttachIfNeeded(textNode);
-        return;
-    }
-    textRenderer->setTextWithOffset(textNode.dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
+
+    bool hadRenderer = textNode.renderer();
+
+    RenderTreePosition renderTreePosition(renderingParentNode->renderer());
+    resolveTextNode(textNode, *renderingParentNode, renderTreePosition);
+
+    if (hadRenderer && textNode.renderer())
+        textNode.renderer()->setTextWithOffset(textNode.dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
 }
 
-static void attachDistributedChildren(InsertionPoint& insertionPoint)
+static void attachChildren(ContainerNode& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition)
+{
+    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
+        ASSERT((!child->renderer() || child->inNamedFlow()) || current.shadowRoot());
+        if (child->renderer()) {
+            renderTreePosition.invalidateNextSibling(*child->renderer());
+            continue;
+        }
+        if (child->isTextNode()) {
+            attachTextRenderer(*toText(child), renderingParentNode, renderTreePosition);
+            continue;
+        }
+        if (child->isElementNode())
+            attachRenderTree(*toElement(child), renderingParentNode, renderTreePosition, nullptr);
+    }
+}
+
+static void attachDistributedChildren(InsertionPoint& insertionPoint, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition)
 {
     if (ShadowRoot* shadowRoot = insertionPoint.containingShadowRoot())
         ContentDistributor::ensureDistribution(shadowRoot);
+
     for (Node* current = insertionPoint.firstDistributed(); current; current = insertionPoint.nextDistributedTo(current)) {
+        if (current->renderer())
+            renderTreePosition.invalidateNextSibling(*current->renderer());
         if (current->isTextNode()) {
             if (current->renderer())
                 continue;
-            attachTextRenderer(*toText(current));
+            attachTextRenderer(*toText(current), renderingParentNode, renderTreePosition);
             continue;
         }
         if (current->isElementNode()) {
-            if (current->renderer())
-                detachRenderTree(*toElement(current));
-            attachRenderTree(*toElement(current), nullptr);
+            Element& currentElement = toElement(*current);
+            if (currentElement.renderer())
+                detachRenderTree(currentElement);
+            attachRenderTree(currentElement, renderingParentNode, renderTreePosition, nullptr);
         }
     }
-}
-
-static void attachChildren(ContainerNode& current)
-{
-    if (isInsertionPoint(current))
-        attachDistributedChildren(toInsertionPoint(current));
-
-    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-        ASSERT((!child->renderer() || child->inNamedFlow()) || current.shadowRoot() || isInsertionPoint(current));
-        if (child->renderer())
-            continue;
-        if (child->isTextNode()) {
-            attachTextRenderer(*toText(child));
-            continue;
-        }
-        if (child->isElementNode())
-            attachRenderTree(*toElement(child), nullptr);
-    }
+    // Use actual children as fallback content.
+    if (!insertionPoint.hasDistribution())
+        attachChildren(insertionPoint, renderingParentNode, renderTreePosition);
 }
 
 static void attachShadowRoot(ShadowRoot& shadowRoot)
 {
-    attachChildren(shadowRoot);
+    ASSERT(shadowRoot.hostElement());
+
+    RenderTreePosition renderTreePosition(shadowRoot.hostElement()->renderer());
+    attachChildren(shadowRoot, *shadowRoot.hostElement(), renderTreePosition);
 
     shadowRoot.clearNeedsStyleRecalc();
     shadowRoot.clearChildNeedsStyleRecalc();
@@ -500,7 +581,7 @@
     current.clearAfterPseudoElement();
 }
 
-static bool needsPseudeElement(Element& current, PseudoId pseudoId)
+static bool needsPseudoElement(Element& current, PseudoId pseudoId)
 {
     if (!current.document().styleSheetCollection().usesBeforeAfterRules())
         return false;
@@ -513,16 +594,16 @@
     return true;
 }
 
-static void attachBeforeOrAfterPseudoElementIfNeeded(Element& current, PseudoId pseudoId)
+static void attachBeforeOrAfterPseudoElementIfNeeded(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
 {
-    if (!needsPseudeElement(current, pseudoId))
+    if (!needsPseudoElement(current, pseudoId))
         return;
     RefPtr<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId);
     setBeforeOrAfterPseudoElement(current, pseudoElement, pseudoId);
-    attachRenderTree(*pseudoElement, nullptr);
+    attachRenderTree(*pseudoElement, current, renderTreePosition, nullptr);
 }
 
-static void attachRenderTree(Element& current, PassRefPtr<RenderStyle> resolvedStyle)
+static void attachRenderTree(Element& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle)
 {
     PostAttachCallbackDisabler callbackDisabler(current.document());
     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
@@ -530,23 +611,26 @@
     if (current.hasCustomStyleResolveCallbacks())
         current.willAttachRenderers();
 
-    createRendererIfNeeded(current, resolvedStyle);
+    createRendererIfNeeded(current, renderingParentNode, renderTreePosition, resolvedStyle);
 
     if (current.parentElement() && current.parentElement()->isInCanvasSubtree())
         current.setIsInCanvasSubtree(true);
 
-    attachBeforeOrAfterPseudoElementIfNeeded(current, BEFORE);
-
     StyleResolverParentPusher parentPusher(&current);
 
-    // When a shadow root exists, it does the work of attaching the children.
+    RenderTreePosition childRenderTreePosition(current.renderer());
+    attachBeforeOrAfterPseudoElementIfNeeded(current, BEFORE, childRenderTreePosition);
+
     if (ShadowRoot* shadowRoot = current.shadowRoot()) {
         parentPusher.push();
         attachShadowRoot(*shadowRoot);
     } else if (current.firstChild())
         parentPusher.push();
 
-    attachChildren(current);
+    if (isInsertionPoint(current))
+        attachDistributedChildren(toInsertionPoint(current), renderingParentNode, renderTreePosition);
+    else
+        attachChildren(current, current, childRenderTreePosition);
 
     current.clearNeedsStyleRecalc();
     current.clearChildNeedsStyleRecalc();
@@ -554,7 +638,7 @@
     if (AXObjectCache* cache = current.document().axObjectCache())
         cache->updateCacheAfterNodeIsAttached(&current);
 
-    attachBeforeOrAfterPseudoElementIfNeeded(current, AFTER);
+    attachBeforeOrAfterPseudoElementIfNeeded(current, AFTER, childRenderTreePosition);
 
     current.updateFocusAppearanceAfterAttachIfNeeded();
 
@@ -656,7 +740,7 @@
     return false;
 }
 
-static Change resolveLocal(Element& current, Change inheritedChange)
+static Change resolveLocal(Element& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, Change inheritedChange)
 {
     Change localChange = Detach;
     RefPtr<RenderStyle> newStyle;
@@ -664,14 +748,14 @@
 
     Document& document = current.document();
     if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
-        newStyle = current.styleForRenderer();
+        newStyle = styleForElement(current, renderingParentNode);
         localChange = determineChange(currentStyle.get(), newStyle.get());
     }
     if (localChange == Detach) {
         if (current.renderer() || current.inNamedFlow())
             detachRenderTree(current, ReattachDetach);
-        attachRenderTree(current, newStyle.release());
-        reattachTextRenderersForWhitespaceOnlySiblingsAfterAttachIfNeeded(current);
+        attachRenderTree(current, renderingParentNode, renderTreePosition, newStyle.release());
+        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
 
         return Detach;
     }
@@ -702,49 +786,57 @@
     return localChange;
 }
 
-static void updateTextStyle(Text& text)
+void resolveTextNode(Text& text, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition)
 {
-    RenderText* renderer = text.renderer();
+    text.clearNeedsStyleRecalc();
 
-    if (!text.needsStyleRecalc())
+    bool hasRenderer = text.renderer();
+    bool needsRenderer = textRendererIsNeeded(text, renderingParentNode);
+    if (hasRenderer) {
+        if (needsRenderer)
+            return;
+        detachTextRenderer(text);
+        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
         return;
-    if (renderer)
-        renderer->setText(text.dataImpl());
-    else {
-        attachTextRenderer(text);
-        reattachTextRenderersForWhitespaceOnlySiblingsAfterAttachIfNeeded(text);
     }
-    text.clearNeedsStyleRecalc();
+    if (!needsRenderer)
+        return;
+    attachTextRenderer(text, renderingParentNode, renderTreePosition);
+    invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
 }
 
-static void resolveShadowTree(ShadowRoot* shadowRoot, Style::Change change)
+static void resolveShadowTree(ShadowRoot& shadowRoot, Element& host, Style::Change change)
 {
-    if (!shadowRoot)
-        return;
-
-    for (Node* child = shadowRoot->firstChild(); child; child = child->nextSibling()) {
-        if (child->isTextNode()) {
-            updateTextStyle(*toText(child));
+    ASSERT(shadowRoot.hostElement() == &host);
+    RenderTreePosition renderTreePosition(host.renderer());
+    for (Node* child = shadowRoot.firstChild(); child; child = child->nextSibling()) {
+        if (child->renderer())
+            renderTreePosition.invalidateNextSibling(*child->renderer());
+        if (child->isTextNode() && child->needsStyleRecalc()) {
+            resolveTextNode(*toText(child), host, renderTreePosition);
             continue;
         }
         if (child->isElementNode())
-            resolveTree(*toElement(child), change);
+            resolveTree(*toElement(child), host, renderTreePosition, change);
     }
 
-    shadowRoot->clearNeedsStyleRecalc();
-    shadowRoot->clearChildNeedsStyleRecalc();
+    shadowRoot.clearNeedsStyleRecalc();
+    shadowRoot.clearChildNeedsStyleRecalc();
 }
 
-static void updateBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId)
+static void updateBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
 {
     if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
-        if (needsPseudeElement(current, pseudoId))
-            resolveTree(*existingPseudoElement, current.needsStyleRecalc() ? Force : change);
+        if (existingPseudoElement->renderer())
+            renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
+
+        if (needsPseudoElement(current, pseudoId))
+            resolveTree(*existingPseudoElement, current, renderTreePosition, current.needsStyleRecalc() ? Force : change);
         else
             clearBeforeOrAfterPseudoElement(current, pseudoId);
         return;
     }
-    attachBeforeOrAfterPseudoElementIfNeeded(current, pseudoId);
+    attachBeforeOrAfterPseudoElementIfNeeded(current, pseudoId, renderTreePosition);
 }
 
 #if PLATFORM(IOS)
@@ -799,7 +891,7 @@
 };
 #endif // PLATFORM(IOS)
 
-void resolveTree(Element& current, Change change)
+void resolveTree(Element& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, Change change)
 {
     ASSERT(change != Detach);
 
@@ -808,8 +900,7 @@
             return;
     }
 
-    ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&current);
-    bool hasParentStyle = renderingParentNode && renderingParentNode->renderStyle();
+    bool hasParentStyle = renderingParentNode.renderStyle();
     bool hasDirectAdjacentRules = current.childrenAffectedByDirectAdjacentRules();
     bool hasIndirectAdjacentRules = current.childrenAffectedByForwardPositionalRules();
 
@@ -821,7 +912,7 @@
         current.resetComputedStyle();
 
     if (hasParentStyle && (change >= Inherit || current.needsStyleRecalc()))
-        change = resolveLocal(current, change);
+        change = resolveLocal(current, renderingParentNode, renderTreePosition, change);
 
     if (change != Detach) {
         StyleResolverParentPusher parentPusher(&current);
@@ -829,11 +920,12 @@
         if (ShadowRoot* shadowRoot = current.shadowRoot()) {
             if (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc()) {
                 parentPusher.push();
-                resolveShadowTree(shadowRoot, change);
+                resolveShadowTree(*shadowRoot, current, change);
             }
         }
 
-        updateBeforeOrAfterPseudoElement(current, change, BEFORE);
+        RenderTreePosition childRenderTreePosition(current.renderer());
+        updateBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
 
         // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
         // For now we will just worry about the common case, since it's a lot trickier to get the second case right
@@ -841,8 +933,10 @@
         bool forceCheckOfNextElementSibling = false;
         bool forceCheckOfAnyElementSibling = false;
         for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-            if (child->isTextNode()) {
-                updateTextStyle(*toText(child));
+            if (child->renderer())
+                childRenderTreePosition.invalidateNextSibling(*child->renderer());
+            if (child->isTextNode() && child->needsStyleRecalc()) {
+                resolveTextNode(*toText(child), current, childRenderTreePosition);
                 continue;
             }
             if (!child->isElementNode())
@@ -853,13 +947,13 @@
                 childElement->setNeedsStyleRecalc();
             if (change >= Inherit || childElement->childNeedsStyleRecalc() || childElement->needsStyleRecalc()) {
                 parentPusher.push();
-                resolveTree(*childElement, change);
+                resolveTree(*childElement, current, childRenderTreePosition, change);
             }
             forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
             forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
         }
 
-        updateBeforeOrAfterPseudoElement(current, change, AFTER);
+        updateBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
     }
 
     current.clearNeedsStyleRecalc();
@@ -894,7 +988,8 @@
         return;
     if (change < Inherit && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
         return;
-    resolveTree(*documentElement, change);
+    RenderTreePosition renderTreePosition(document.renderView());
+    resolveTree(*documentElement, document, renderTreePosition, change);
 }
 
 void detachRenderTree(Element& element)
--- a/modules/web/src/main/native/Source/WebCore/svg/SVGElement.cpp	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/svg/SVGElement.cpp	Thu Mar 10 14:16:20 2016 -0800
@@ -768,18 +768,12 @@
     contextElement->synchronizeSystemLanguage();
 }
 
-PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
+PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer(RenderStyle& parentStyle)
 {
     if (!correspondingElement())
-        return document().ensureStyleResolver().styleForElement(this);
+        return document().ensureStyleResolver().styleForElement(this, &parentStyle);
 
-    RenderStyle* style = 0;
-    if (Element* parent = parentOrShadowHostElement()) {
-        if (auto renderer = parent->renderer())
-            style = &renderer->style();
-    }
-
-    return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
+    return document().ensureStyleResolver().styleForElement(correspondingElement(), &parentStyle, DisallowStyleSharing);
 }
 
 MutableStyleProperties* SVGElement::animatedSMILStyleProperties() const
--- a/modules/web/src/main/native/Source/WebCore/svg/SVGElement.h	Thu Mar 10 01:24:59 2016 -0800
+++ b/modules/web/src/main/native/Source/WebCore/svg/SVGElement.h	Thu Mar 10 14:16:20 2016 -0800
@@ -112,7 +112,7 @@
     void synchronizeAnimatedSVGAttribute(const QualifiedName&) const;
     static void synchronizeAllAnimatedSVGAttribute(SVGElement*);
 
-    virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
 
     static void synchronizeRequiredFeatures(SVGElement* contextElement);
     static void synchronizeRequiredExtensions(SVGElement* contextElement);
--- a/tests/system/src/test/java/test/util/Util.java	Thu Mar 10 01:24:59 2016 -0800
+++ b/tests/system/src/test/java/test/util/Util.java	Thu Mar 10 14:16:20 2016 -0800
@@ -192,7 +192,7 @@
 
         String jfxdir = getJfxrtDir(classpath);
         Assert.assertNotNull("failed to find jfxdir",jfxdir);
-        cmd.add("-Djava.ext.dirs=" + jfxdir);
+        cmd.add("-Xbootclasspath/a:" + jfxdir + "/" + "jfxrt.jar");
 
         cmd.add("-cp");
         cmd.add(classpath);