Commit 4e246b2e authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Don't let legacy layout re-enter layout of a scrollable block node.

We'd end up re-entering NGBlockNode::CopyFragmentDataToLayoutBox() for
the same node.

After layout of a fragment, NGBlockNode::CopyFragmentDataToLayoutBox() would
call LayoutBlock::UpdateAfterLayout(), which would call
scrollbar was toggled, it'd go ahead and call UpdateLayout() on the object,
which would take us back into the NG layout machinery, on the same node, via
Finally we'd re-enter NGBlockNode::CopyFragmentDataToLayoutBox(), causing misc
kinds of misery, such as not being able to paint the block at all. For
multicol, there'd even be a DCHECK failure "Variable fragment inline size not
supported", because the code got confused as to whether a fragment was a first
fragment or not.

LayoutBox: :UpdateAfterLayout(), which would call
PaintLayer: :UpdateSizeAndScrollingAfterLayout(), which would call
PaintLayerScrollableArea: :UpdateAfterLayout(). If this code detected that a
LayoutNGBlockFlow: :UpdateBlockLayout(), further to NGBlockNode::Layout().
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_layout_ng;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I832372223e324682bb4e38b3177dce30093df2e1
Reviewed-on: https://chromium-review.googlesource.com/824265
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#524039}
parent 809aae3c
...@@ -409,7 +409,6 @@ crbug.com/591099 compositing/rtl/rtl-iframe-fixed.html [ Failure ] ...@@ -409,7 +409,6 @@ crbug.com/591099 compositing/rtl/rtl-iframe-fixed.html [ Failure ]
crbug.com/591099 compositing/rtl/rtl-iframe-relative.html [ Failure ] crbug.com/591099 compositing/rtl/rtl-iframe-relative.html [ Failure ]
crbug.com/591099 compositing/rtl/rtl-overflow-scrolling.html [ Failure ] crbug.com/591099 compositing/rtl/rtl-overflow-scrolling.html [ Failure ]
crbug.com/591099 compositing/rtl/rtl-relative.html [ Failure ] crbug.com/591099 compositing/rtl/rtl-relative.html [ Failure ]
crbug.com/591099 compositing/scrollbars/nested-overlay-scrollbars.html [ Crash ]
crbug.com/591099 compositing/self-painting-layers.html [ Failure ] crbug.com/591099 compositing/self-painting-layers.html [ Failure ]
crbug.com/591099 compositing/shadows/shadow-drawing.html [ Failure ] crbug.com/591099 compositing/shadows/shadow-drawing.html [ Failure ]
crbug.com/591099 compositing/sibling-positioning.html [ Failure ] crbug.com/591099 compositing/sibling-positioning.html [ Failure ]
...@@ -10613,7 +10612,6 @@ crbug.com/591099 virtual/spv175/compositing/rtl/rtl-iframe-fixed.html [ Failure ...@@ -10613,7 +10612,6 @@ crbug.com/591099 virtual/spv175/compositing/rtl/rtl-iframe-fixed.html [ Failure
crbug.com/591099 virtual/spv175/compositing/rtl/rtl-iframe-relative.html [ Failure ] crbug.com/591099 virtual/spv175/compositing/rtl/rtl-iframe-relative.html [ Failure ]
crbug.com/591099 virtual/spv175/compositing/rtl/rtl-overflow-scrolling.html [ Failure ] crbug.com/591099 virtual/spv175/compositing/rtl/rtl-overflow-scrolling.html [ Failure ]
crbug.com/591099 virtual/spv175/compositing/rtl/rtl-relative.html [ Failure ] crbug.com/591099 virtual/spv175/compositing/rtl/rtl-relative.html [ Failure ]
crbug.com/591099 virtual/spv175/compositing/scrollbars/nested-overlay-scrollbars.html [ Crash ]
crbug.com/591099 virtual/spv175/compositing/self-painting-layers.html [ Failure ] crbug.com/591099 virtual/spv175/compositing/self-painting-layers.html [ Failure ]
crbug.com/591099 virtual/spv175/compositing/shadows/shadow-drawing.html [ Failure ] crbug.com/591099 virtual/spv175/compositing/shadows/shadow-drawing.html [ Failure ]
crbug.com/591099 virtual/spv175/compositing/sibling-positioning.html [ Failure ] crbug.com/591099 virtual/spv175/compositing/sibling-positioning.html [ Failure ]
......
<!DOCTYPE html>
<style>
/* Prevent auto viewport overflow, because that would trigger another
layout pass, hiding the bug. */
body { overflow:hidden; }
</style>
<p>There should be a green square below. No red, orange or yellow.</p>
<div style="width:50px; height:50px; background:green;"></div>
<!DOCTYPE html>
<style>
/* Prevent auto viewport overflow, because that would trigger another
layout pass, hiding the bug. */
body { overflow:hidden; }
</style>
<p>There should be a green square below. No red, orange or yellow.</p>
<!-- The outer container is there to clip painting of the scrollbar,
to make it easier to write a reftest. -->
<div style="overflow:hidden; width:50px; height:50px; background:orange;">
<!-- The overflow:auto block needs auto width to be able to
reproduce the bug. Use a wide wrapper, so that the scrollbar
gets clipped. -->
<div style="width:100px; background:red;">
<div style="overflow:auto; height:50px; background:yellow;">
<div style="height:51px; background:green;"></div>
</div>
</div>
</div>
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutNGBlockFlow (positioned) DIV id='outer'",
"position": [8, 8],
"bounds": [404, 404]
},
{
"name": "Scrolling Layer",
"position": [10, 10],
"bounds": [400, 400],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"position": [10, 10],
"bounds": [400, 704],
"transform": 1
},
{
"name": "LayoutNGBlockFlow (positioned) DIV id='inner'",
"position": [10, 510],
"bounds": [204, 204],
"transform": 1
},
{
"name": "Scrolling Layer",
"position": [12, 512],
"bounds": [200, 200],
"drawsContent": false,
"transform": 1
},
{
"name": "Scrolling Contents Layer",
"position": [12, 512],
"bounds": [5000, 9000],
"transform": 1
},
{
"name": "Squashing Containment Layer",
"position": [10, 10],
"drawsContent": false,
"transform": 1
},
{
"name": "LayoutNGBlockFlow (positioned) DIV id='grey'",
"position": [12, 512],
"bounds": [100, 800],
"contentsOpaque": true,
"backgroundColor": "#808080",
"transform": 1
},
{
"name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV id='spacer')",
"position": [12, 2512],
"bounds": [5000, 1000],
"transform": 1
},
{
"name": "Overflow Controls Host Layer",
"position": [12, 512],
"bounds": [204, 204],
"drawsContent": false,
"transform": 1
},
{
"name": "Horizontal Scrollbar Layer",
"position": [14, 707],
"bounds": [193, 7],
"drawsContent": false,
"transform": 1
},
{
"name": "Vertical Scrollbar Layer",
"position": [207, 514],
"bounds": [7, 193],
"drawsContent": false,
"transform": 1
},
{
"name": "Scroll Corner Layer",
"position": [207, 707],
"bounds": [7, 7],
"transform": 1
},
{
"name": "Overflow Controls Host Layer",
"position": [8, 8],
"bounds": [404, 404],
"drawsContent": false
},
{
"name": "Vertical Scrollbar Layer",
"position": [403, 10],
"bounds": [7, 400],
"drawsContent": false
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, -304, 0, 1]
],
"flattenInheritedTransform": false
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [800, 600],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [800, 600],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "LayoutNGBlockFlow (positioned) DIV id='outer'",
"position": [8, 8],
"bounds": [404, 404]
},
{
"name": "Scrolling Layer",
"position": [10, 10],
"bounds": [400, 400],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"position": [10, 10],
"bounds": [400, 704],
"transform": 1
},
{
"name": "LayoutNGBlockFlow (positioned) DIV id='inner'",
"position": [10, 510],
"bounds": [204, 204],
"transform": 1
},
{
"name": "Scrolling Layer",
"position": [12, 512],
"bounds": [200, 200],
"drawsContent": false,
"transform": 1
},
{
"name": "Scrolling Contents Layer",
"position": [12, 512],
"bounds": [5000, 9000],
"transform": 1
},
{
"name": "Squashing Containment Layer",
"position": [10, 10],
"drawsContent": false,
"transform": 1
},
{
"name": "LayoutNGBlockFlow (positioned) DIV id='grey'",
"position": [12, 512],
"bounds": [100, 800],
"contentsOpaque": true,
"backgroundColor": "#808080",
"transform": 1
},
{
"name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV id='spacer')",
"position": [12, 2512],
"bounds": [5000, 1000],
"transform": 1
},
{
"name": "Overflow Controls Host Layer",
"position": [12, 512],
"bounds": [204, 204],
"drawsContent": false,
"transform": 1
},
{
"name": "Horizontal Scrollbar Layer",
"position": [14, 707],
"bounds": [193, 7],
"drawsContent": false,
"transform": 1
},
{
"name": "Vertical Scrollbar Layer",
"position": [207, 514],
"bounds": [7, 193],
"drawsContent": false,
"transform": 1
},
{
"name": "Scroll Corner Layer",
"position": [207, 707],
"bounds": [7, 7],
"transform": 1
},
{
"name": "Overflow Controls Host Layer",
"position": [8, 8],
"bounds": [404, 404],
"drawsContent": false
},
{
"name": "Vertical Scrollbar Layer",
"position": [403, 10],
"bounds": [7, 400],
"drawsContent": false
}
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, -304, 0, 1]
],
"flattenInheritedTransform": false
}
]
}
<!DOCTYPE html>
<p>There should be a hotpink square below.</p>
<div style="width:50px; height:50px; background:hotpink;"></div>
<!DOCTYPE html>
<p>There should be a hotpink square below.</p>
<div id="multicol" style="columns:3; column-fill:auto; column-gap:0; height:50px;">
<div style="overflow:auto; height:100px; background:hotpink;"></div>
</div>
<script>
document.body.offsetTop;
document.getElementById("multicol").style.width = "75px";
</script>
...@@ -48,4 +48,15 @@ bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow* block) { ...@@ -48,4 +48,15 @@ bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow* block) {
return false; return false;
} }
bool IsManagedByLayoutNG(const LayoutObject& object) {
if (!object.IsLayoutNGMixin())
return false;
const auto* containing_block = object.ContainingBlock();
if (!containing_block)
return false;
if (containing_block->IsLayoutFlowThread())
containing_block = containing_block->ContainingBlock();
return containing_block && containing_block->IsLayoutNGMixin();
}
} // namespace blink } // namespace blink
...@@ -24,6 +24,10 @@ LayoutObject* GetLayoutObjectForParentNode(LayoutObject*); ...@@ -24,6 +24,10 @@ LayoutObject* GetLayoutObjectForParentNode(LayoutObject*);
// established by |block| will be inline; see LayoutObject::ChildrenInline(). // established by |block| will be inline; see LayoutObject::ChildrenInline().
bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow*); bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow*);
// Return true if the layout object is a LayoutNG object that is managed by the
// LayoutNG engine (i.e. its containing block is a LayoutNG object as well).
bool IsManagedByLayoutNG(const LayoutObject&);
} // namespace blink } // namespace blink
#endif // LegacyLayoutTreeWalking_h #endif // LegacyLayoutTreeWalking_h
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include "core/layout/LayoutTheme.h" #include "core/layout/LayoutTheme.h"
#include "core/layout/LayoutView.h" #include "core/layout/LayoutView.h"
#include "core/layout/api/LayoutBoxItem.h" #include "core/layout/api/LayoutBoxItem.h"
#include "core/layout/ng/legacy_layout_tree_walking.h"
#include "core/loader/DocumentLoader.h" #include "core/loader/DocumentLoader.h"
#include "core/page/ChromeClient.h" #include "core/page/ChromeClient.h"
#include "core/page/FocusController.h" #include "core/page/FocusController.h"
...@@ -876,10 +877,13 @@ void PaintLayerScrollableArea::UpdateAfterLayout() { ...@@ -876,10 +877,13 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
Box().GetDocument().SetAnnotatedRegionsDirty(true); Box().GetDocument().SetAnnotatedRegionsDirty(true);
// Our proprietary overflow: overlay value doesn't trigger a layout. // Our proprietary overflow: overlay value doesn't trigger a layout.
if ((horizontal_scrollbar_should_change && // If the box is managed by LayoutNG, don't go here. We don't want to
Box().Style()->OverflowX() != EOverflow::kOverlay) || // re-enter the NG layout algorithm for this box from here.
(vertical_scrollbar_should_change && if (((horizontal_scrollbar_should_change &&
Box().Style()->OverflowY() != EOverflow::kOverlay)) { Box().Style()->OverflowX() != EOverflow::kOverlay) ||
(vertical_scrollbar_should_change &&
Box().Style()->OverflowY() != EOverflow::kOverlay)) &&
!IsManagedByLayoutNG(Box())) {
if ((vertical_scrollbar_should_change && if ((vertical_scrollbar_should_change &&
Box().IsHorizontalWritingMode()) || Box().IsHorizontalWritingMode()) ||
(horizontal_scrollbar_should_change && (horizontal_scrollbar_should_change &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment