Commit 1e103bbd authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

Fix fragment data under overflow clip under multicol

This fixes fragment data LogicalTopInFlowThread for overflowing contents
under clip under multicol. Previously the overflowing parts created
phantom fragments as if they were overflow:visible. Now the overflowing
parts are under the last fragment of the clipping element. They will be
painted correctly when they scrolls into the container clip rect.

Bug: 1063043, 1064015

Change-Id: Ie8d60250736b0a5074872e7ef8d021c5731f9b40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2132934Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#756142}
parent 98491354
......@@ -3007,6 +3007,7 @@ PaintPropertyTreeBuilder::ContextForFragment(
// This will be used in the loop finding matching fragment from ancestor flow
// threads after no matching from parent_fragments.
LayoutUnit logical_top_in_containing_flow_thread;
bool crossed_flow_thread = false;
if (object_.IsLayoutFlowThread()) {
const auto& flow_thread = ToLayoutFlowThread(object_);
......@@ -3025,6 +3026,7 @@ PaintPropertyTreeBuilder::ContextForFragment(
return context;
}
}
crossed_flow_thread = true;
} else {
bool parent_is_under_same_flow_thread;
auto* pagination_layer =
......@@ -3057,6 +3059,7 @@ PaintPropertyTreeBuilder::ContextForFragment(
}
logical_top_in_containing_flow_thread = logical_top_in_flow_thread;
crossed_flow_thread = !parent_is_under_same_flow_thread;
}
// Found no matching parent fragment. Use parent_fragments[0] to inherit
......@@ -3081,14 +3084,35 @@ PaintPropertyTreeBuilder::ContextForFragment(
if (!container->FirstFragment().HasLocalBorderBoxProperties())
continue;
for (const auto* fragment = &container->FirstFragment(); fragment;
fragment = fragment->NextFragment()) {
if (fragment->LogicalTopInFlowThread() ==
logical_top_in_containing_flow_thread) {
// Found a matching fragment in an ancestor container. Use the
// container's content clip as the clip state.
context.current.clip = &fragment->PostOverflowClip();
return context;
const FragmentData* container_fragment = &container->FirstFragment();
while (container_fragment->LogicalTopInFlowThread() <
logical_top_in_containing_flow_thread &&
container_fragment->NextFragment())
container_fragment = container_fragment->NextFragment();
if (container_fragment->LogicalTopInFlowThread() ==
logical_top_in_containing_flow_thread) {
// Found a matching fragment in an ancestor container. Use the
// container's content clip as the clip state.
context.current.clip = &container_fragment->PostOverflowClip();
return context;
}
// We didn't find corresponding fragment in the container because the
// fragment fully overflows the container. If the container has overflow
// clip, then this fragment should be under |container_fragment|.
// This works only when the current fragment and the overflow clip are under
// the same flow thread. In other cases, we just leave it broken, which will
// be fixed by LayoutNG block fragments hopefully.
if (!crossed_flow_thread) {
if (const auto* container_properties =
container_fragment->PaintProperties()) {
if (const auto* overflow_clip = container_properties->OverflowClip()) {
context.logical_top_in_flow_thread =
container_fragment->LogicalTopInFlowThread();
context.current.clip = overflow_clip;
return context;
}
}
}
......@@ -3097,6 +3121,7 @@ PaintPropertyTreeBuilder::ContextForFragment(
FragmentLogicalTopInParentFlowThread(
ToLayoutFlowThread(*container),
logical_top_in_containing_flow_thread);
crossed_flow_thread = true;
}
}
......@@ -3181,8 +3206,16 @@ void PaintPropertyTreeBuilder::CreateFragmentContextsInFlowThread(
}
// Match to parent fragments from the same containing flow thread.
new_fragment_contexts.push_back(
ContextForFragment(fragment_clip, logical_top_in_flow_thread));
auto fragment_context =
ContextForFragment(fragment_clip, logical_top_in_flow_thread);
// ContextForFragment may override logical_top_in_flow_thread.
logical_top_in_flow_thread = fragment_context.logical_top_in_flow_thread;
// Avoid fragment with duplicated overridden logical_top_in_flow_thread.
if (new_fragment_contexts.size() &&
new_fragment_contexts.back().logical_top_in_flow_thread ==
logical_top_in_flow_thread)
break;
new_fragment_contexts.push_back(fragment_context);
if (current_fragment_data) {
if (!current_fragment_data->NextFragment())
......
......@@ -4322,6 +4322,33 @@ TEST_P(PaintPropertyTreeBuilderTest, LayerUnderOverflowClipUnderMultiColumn) {
EXPECT_EQ(1u, NumFragments(GetLayoutObjectByElementId("layer")));
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowClipUnderMultiColumn) {
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; }</style>
<div style='columns: 4; height: 100px; column-fill: auto; column-gap: 0'>
<div id='clip' style='height: 200px; overflow: hidden'>
<div id='child1' style='height: 400px'></div>
<div id='child2' style='height: 400px'></div>
</div>
</div>
)HTML");
const auto* clip = GetLayoutObjectByElementId("clip");
ASSERT_EQ(2u, NumFragments(clip));
EXPECT_EQ(LayoutUnit(), FragmentAt(clip, 0).LogicalTopInFlowThread());
EXPECT_EQ(LayoutUnit(100), FragmentAt(clip, 1).LogicalTopInFlowThread());
const auto* child1 = GetLayoutObjectByElementId("child1");
ASSERT_EQ(2u, NumFragments(child1));
EXPECT_EQ(LayoutUnit(), FragmentAt(child1, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(), FragmentAt(child1, 0).PaintOffset());
EXPECT_EQ(LayoutUnit(100), FragmentAt(child1, 1).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(200, -100), FragmentAt(child1, 1).PaintOffset());
const auto* child2 = GetLayoutObjectByElementId("child2");
ASSERT_EQ(1u, NumFragments(child2));
EXPECT_EQ(LayoutUnit(100), FragmentAt(child2, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(200, 300), FragmentAt(child2, 0).PaintOffset());
}
TEST_P(PaintPropertyTreeBuilderTest, CompositedUnderMultiColumn) {
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; }</style>
......
......@@ -1038,6 +1038,7 @@ crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/mult
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-nested-margin-004.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-nested-margin-005.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-overflow-000.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-overflow-clip.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-overflowing-001.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-reduce-000.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-000.xht [ Failure ]
......
<!DOCTYPE html>
<style>
.multicol {
column-count: 3;
}
.parent {
background: green;
height: 50px;
}
</style>
<div class="multicol">
<div class="parent"></div>
<div class="parent"></div>
<div class="parent"></div>
</div>
<!DOCTYPE html>
<title>CSS Multi-column Layout Test: multicol with overflow-clipped content</title>
<link rel="help" href="https://www.w3.org/TR/css-multicol-1/">
<link rel="match" href="multicol-overflow-clip-ref.html">
<meta name="assert" content="Overflow clip should work under multicol.">
<style>
.multicol {
column-count: 3;
}
.parent {
background: green;
height: 50px;
overflow: hidden;
}
.child2 {
margin-top: 50px;
background: darkred;
color: red;
height: 100px;
}
</style>
<div class="multicol">
<div class="parent">
<div class="child2">This should be hidden.</div>
</div>
<div class="parent">
<div class="child2">This should be hidden.</div>
</div>
<div class="parent">
<div class="child2">This should be hidden.</div>
</div>
</div>
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