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