Title: [230555] trunk/Tools
Revision
230555
Author
za...@apple.com
Date
2018-04-11 21:19:30 -0700 (Wed, 11 Apr 2018)

Log Message

[LayoutReloaded] Introduce needsLayout flag
https://bugs.webkit.org/show_bug.cgi?id=184527

Reviewed by Antti Koivisto.

Use the formatting state to mark boxes dirty.

* LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js:
(BlockFormattingContext.prototype.layout):
(BlockFormattingContext.prototype._firstInFlowChildWithNeedsLayout):
(BlockFormattingContext.prototype._nextInFlowSiblingWithNeedsLayout):
(BlockFormattingContext):
* LayoutReloaded/FormattingContext/FormattingContext.js:
(FormattingContext.prototype._layoutOutOfFlowDescendants):
* LayoutReloaded/FormattingState/FormattingState.js:
(FormattingState):
(FormattingState.prototype.markNeedsLayout):
(FormattingState.prototype.clearNeedsLayout):
(FormattingState.prototype.needsLayout):
(FormattingState.prototype.layoutNeeded):
(FormattingState.prototype._markSubTreeNeedsLayout):
* LayoutReloaded/LayoutState.js:
(LayoutState.prototype.formattingStateForBox):
(LayoutState.prototype.setNeedsLayout):
(LayoutState.prototype.needsLayout):
* LayoutReloaded/LayoutTree/Box.js:
(Layout.Box.prototype.isFormattingContextDescendant):
* LayoutReloaded/LayoutTree/Container.js:
(Layout.Container.prototype.isContainingBlockDescendant):

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (230554 => 230555)


--- trunk/Tools/ChangeLog	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/ChangeLog	2018-04-12 04:19:30 UTC (rev 230555)
@@ -1,3 +1,35 @@
+2018-04-11  Zalan Bujtas  <za...@apple.com>
+
+        [LayoutReloaded] Introduce needsLayout flag
+        https://bugs.webkit.org/show_bug.cgi?id=184527
+
+        Reviewed by Antti Koivisto.
+
+        Use the formatting state to mark boxes dirty.
+
+        * LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js:
+        (BlockFormattingContext.prototype.layout):
+        (BlockFormattingContext.prototype._firstInFlowChildWithNeedsLayout):
+        (BlockFormattingContext.prototype._nextInFlowSiblingWithNeedsLayout):
+        (BlockFormattingContext):
+        * LayoutReloaded/FormattingContext/FormattingContext.js:
+        (FormattingContext.prototype._layoutOutOfFlowDescendants):
+        * LayoutReloaded/FormattingState/FormattingState.js:
+        (FormattingState):
+        (FormattingState.prototype.markNeedsLayout):
+        (FormattingState.prototype.clearNeedsLayout):
+        (FormattingState.prototype.needsLayout):
+        (FormattingState.prototype.layoutNeeded):
+        (FormattingState.prototype._markSubTreeNeedsLayout):
+        * LayoutReloaded/LayoutState.js:
+        (LayoutState.prototype.formattingStateForBox):
+        (LayoutState.prototype.setNeedsLayout):
+        (LayoutState.prototype.needsLayout):
+        * LayoutReloaded/LayoutTree/Box.js:
+        (Layout.Box.prototype.isFormattingContextDescendant):
+        * LayoutReloaded/LayoutTree/Container.js:
+        (Layout.Container.prototype.isContainingBlockDescendant):
+
 2018-04-11  Jonathan Bedard  <jbed...@apple.com>
 
         Fix TestInvocation class for newer versions of clang.

Modified: trunk/Tools/LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js (230554 => 230555)


--- trunk/Tools/LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/LayoutReloaded/FormattingContext/BlockFormatting/BlockFormattingContext.js	2018-04-12 04:19:30 UTC (rev 230555)
@@ -35,8 +35,7 @@
 
         // This is a post-order tree traversal layout.
         // The root container layout is done in the formatting context it lives in, not that one it creates, so let's start with the first child.
-        if (this.formattingRoot().firstInFlowOrFloatChild())
-            this._addToLayoutQueue(this.formattingRoot().firstInFlowOrFloatChild());
+        this._addToLayoutQueue(this._firstInFlowChildWithNeedsLayout(this.formattingRoot()));
         // 1. Go all the way down to the leaf node
         // 2. Compute static position and width as we travers down
         // 3. As we climb back on the tree, compute height and finialize position
@@ -51,9 +50,10 @@
                     this.layoutState().layout(layoutBox);
                     break;
                 }
-                if (!layoutBox.isContainer() || !layoutBox.hasInFlowOrFloatChild())
+                let childToLayout = this._firstInFlowChildWithNeedsLayout(layoutBox);
+                if (!childToLayout)
                     break;
-                this._addToLayoutQueue(layoutBox.firstInFlowOrFloatChild());
+                this._addToLayoutQueue(childToLayout);
             }
 
             // Climb back on the ancestors and compute height/final position.
@@ -67,8 +67,10 @@
                 this._placeInFlowPositionedChildren(layoutBox);
                 // We are done with laying out this box.
                 this._removeFromLayoutQueue(layoutBox);
-                if (layoutBox.nextInFlowOrFloatSibling()) {
-                    this._addToLayoutQueue(layoutBox.nextInFlowOrFloatSibling());
+                this.formattingState().clearNeedsLayout(layoutBox);
+                let nextSiblingToLayout = this._nextInFlowSiblingWithNeedsLayout(layoutBox);
+                if (nextSiblingToLayout) {
+                    this._addToLayoutQueue(nextSiblingToLayout);
                     break;
                 }
             }
@@ -77,6 +79,7 @@
         this._placeInFlowPositionedChildren(this.formattingRoot());
         // And take care of out-of-flow boxes as the final step.
         this._layoutOutOfFlowDescendants();
+        ASSERT(!this.formattingState().layoutNeeded());
    }
 
     computeWidth(layoutBox) {
@@ -175,4 +178,22 @@
         }
         return bottom;
     }
+
+    _firstInFlowChildWithNeedsLayout(layoutBox) {
+        if (!layoutBox.isContainer())
+            return null;
+        for (let child = layoutBox.firstInFlowOrFloatChild(); child; child = child.nextInFlowOrFloatSibling()) {
+            if (this.formattingState().needsLayout(child))
+                return child;
+        }
+        return null;
+    }
+
+    _nextInFlowSiblingWithNeedsLayout(layoutBox) {
+        for (let sibling = layoutBox.nextInFlowOrFloatSibling(); sibling; sibling = sibling.nextInFlowOrFloatSibling()) {
+            if (this.formattingState().needsLayout(sibling))
+                return sibling;
+        }
+        return null;
+    }
 }

Modified: trunk/Tools/LayoutReloaded/FormattingContext/FormattingContext.js (230554 => 230555)


--- trunk/Tools/LayoutReloaded/FormattingContext/FormattingContext.js	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/LayoutReloaded/FormattingContext/FormattingContext.js	2018-04-12 04:19:30 UTC (rev 230555)
@@ -165,6 +165,7 @@
             this._computeOutOfFlowHeight(outOfFlowBox);
             this._computeOutOfFlowPosition(outOfFlowBox);
             this._removeFromLayoutQueue(outOfFlowBox);
+            this.formattingState().clearNeedsLayout(outOfFlowBox);
         }
     }
 

Modified: trunk/Tools/LayoutReloaded/FormattingState/FormattingState.js (230554 => 230555)


--- trunk/Tools/LayoutReloaded/FormattingState/FormattingState.js	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/LayoutReloaded/FormattingState/FormattingState.js	2018-04-12 04:19:30 UTC (rev 230555)
@@ -29,6 +29,8 @@
         this.m_formattingRoot = formattingRoot;
         this.m_floatingState = null;
         this.m_displayToLayout = new Map();
+        this.m_needsLayoutBoxList = new Map();
+        this._markSubTreeNeedsLayout(formattingRoot);
     }
 
     formattingRoot() {
@@ -86,4 +88,34 @@
         ASSERT(!layoutBox.parent());
         return this.layoutState().initialDisplayBox();
     }
+
+    markNeedsLayout(layoutBox) {
+        this.m_needsLayoutBoxList.set(layoutBox);
+    }
+
+    clearNeedsLayout(layoutBox) {
+        this.m_needsLayoutBoxList.delete(layoutBox);
+    }
+
+    needsLayout(layoutBox) {
+        return this.m_needsLayoutBoxList.has(layoutBox);
+    }
+
+    // This should just be needsLayout()
+    layoutNeeded() {
+        return this.m_needsLayoutBoxList.size;
+    }
+
+    _markSubTreeNeedsLayout(subTreeRoot) {
+        if (!subTreeRoot)
+            return;
+        // Only mark children that actually belong to this formatting context/state.
+        if (this.formattingRoot().isFormattingContextDescendant(subTreeRoot))
+            this.markNeedsLayout(subTreeRoot);
+        if (!subTreeRoot.isContainer() || !subTreeRoot.hasChild())
+            return;
+        for (let child = subTreeRoot.firstChild(); child; child = child.nextSibling())
+            this._markSubTreeNeedsLayout(child);
+    }
+
 }

Modified: trunk/Tools/LayoutReloaded/LayoutState.js (230554 => 230555)


--- trunk/Tools/LayoutReloaded/LayoutState.js	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/LayoutReloaded/LayoutState.js	2018-04-12 04:19:30 UTC (rev 230555)
@@ -64,16 +64,30 @@
     }
 
     formattingStateForBox(layoutBox) {
-        // FIXME: We should probably cache this somewhere
-        let formattingState = null;
-        let ancestor = layoutBox.containingBlock();
-        do {
-            formattingState = this.m_formattingStates.get(ancestor);
-            ancestor = ancestor.containingBlock();
-        } while (!formattingState);
-        return formattingState;
+        for (let formattingState of this.formattingStates()) {
+            if (formattingState[0].isFormattingContextDescendant(layoutBox))
+                return formattingState[1];
+        }
+        ASSERT_NOT_REACHED();
+        return null;
     }
 
+    setNeedsLayout(layoutBox) {
+        let formattingState = this.formattingStateForBox(layoutBox);
+        // Newly created formatting state will obviously mark all the boxes dirty.
+        if (!formattingState)
+            return;
+        formattingState.setNeedsLayout(layoutBox);
+    }
+
+    needsLayout() {
+        for (let formattingState of this.formattingStates()) {
+            if (formattingState[1].layoutNeeded())
+                return true;
+        }
+        return false;
+    }
+
     initialDisplayBox() {
         return this.m_initialDisplayBox;
     }

Modified: trunk/Tools/LayoutReloaded/LayoutTree/Box.js (230554 => 230555)


--- trunk/Tools/LayoutReloaded/LayoutTree/Box.js	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/LayoutReloaded/LayoutTree/Box.js	2018-04-12 04:19:30 UTC (rev 230555)
@@ -165,6 +165,18 @@
         return false;
     }
 
+    isFormattingContextDescendant(layoutBox) {
+        ASSERT(this.establishesFormattingContext());
+        // If we hit the "this" while climbing up on the containing block chain and we don't pass a formatting context root -> box is part of this box's formatting context.
+        for (let containingBlock = layoutBox.containingBlock(); containingBlock; containingBlock = containingBlock.containingBlock()) {
+            if (containingBlock == this)
+                return true;
+            if (containingBlock.establishesFormattingContext())
+                return false;
+        }
+        return false;
+    }
+
     isPositioned() {
         return this.isOutOfFlowPositioned() || this.isRelativelyPositioned();
     }

Modified: trunk/Tools/LayoutReloaded/LayoutTree/Container.js (230554 => 230555)


--- trunk/Tools/LayoutReloaded/LayoutTree/Container.js	2018-04-12 03:55:51 UTC (rev 230554)
+++ trunk/Tools/LayoutReloaded/LayoutTree/Container.js	2018-04-12 04:19:30 UTC (rev 230555)
@@ -85,6 +85,18 @@
         return !!this.firstInFlowOrFloatChild();
     }
 
+    isContainingBlockDescendant(layoutBox) {
+        ASSERT(layoutBox);
+        // If we hit the "this" while climbing up on the containing block chain -> box is part of this box's containing block subtree.
+        let containingBlock = layoutBox.containingBlock();
+        while (containingBlock) {
+            if (containingBlock == this)
+                return true;
+            containingBlock = containingBlock.containingBlock();
+        }
+        return false;
+    }
+
     outOfFlowDescendants() {
         if (!this.isPositioned())
             return new Array();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to