Commit 1e6957e6 authored by Aleks Totic's avatar Aleks Totic Committed by Commit Bot

Always add positioned objects to Legacy OOF container.

Add LayoutNGBlockFlow::CachedLayoutResultForTesting method to enable 
fragment access from unit tests.

# Reason for patch:

Legacy has a fast layout code path that does not call
LayoutNGBlockFlow::UpdateBlockLayout. This path updates 
overflow, and position of OOF descendants. Because of this, 
Legacy containers must know about all OOF descendants.

Existing code did not let Legacy containers know about NG OOF 
descendants. This CL fixes this.

# Unit tests problems.

This patch will affect future webkit_unit_tests. NGBlockNode::Layout 
will DCHECK if done outside of the performLayout cycle if 
NGBlockNode has OOF descendants. 

The core cause is this:
NGBlockNode::CopyFragmentToLegacyLayout calls 
LayoutBox::LayoutPositionedObjects. LayoutPositionedObjects 
asserts that View()->IsInPerformLayout()

This patch fixes four existing failing tests.

1) NGBlockLayoutAlgorithmTest.CollapsingMarginsEmptyBlockWithClearance
Fixed by inspecting LayoutObjects instead of fragments.

2) NGOutOfFlowLayoutPartTest.FixedInsideAbs
Fixed by 

3) NGOutOfFlowLayoutPartTest.OrthogonalWritingMode1
4) NGOutOfFlowLayoutPartTest.OrthogonalWritingMode2
Removed, code already covered by existing LayoutTests.

Bug: 740993
Change-Id: I3a87ef5cdac883517bc3db33e0569668161ff806
Reviewed-on: https://chromium-review.googlesource.com/722760
Commit-Queue: Aleks Totic <atotic@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#510149}
parent e53faad1
...@@ -140,6 +140,16 @@ void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() { ...@@ -140,6 +140,16 @@ void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
} }
if (!logical_top.IsAuto()) if (!logical_top.IsAuto())
static_block = ValueForLength(logical_top, container->LogicalHeight()); static_block = ValueForLength(logical_top, container->LogicalHeight());
// Legacy static position is relative to padding box.
// Convert to border box.
NGBoxStrut border_strut =
ComputeBorders(*constraint_space, *container_style);
if (parent_style->IsLeftToRightDirection())
static_inline += border_strut.inline_start;
else
static_inline -= border_strut.inline_end;
static_block += border_strut.block_start;
} }
if (!parent_style->IsLeftToRightDirection()) if (!parent_style->IsLeftToRightDirection())
static_inline = containing_block_logical_width - static_inline; static_inline = containing_block_logical_width - static_inline;
...@@ -168,9 +178,9 @@ void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() { ...@@ -168,9 +178,9 @@ void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
DCHECK(css_container->IsBox()); DCHECK(css_container->IsBox());
NGOutOfFlowLayoutPart(NGBlockNode(ToLayoutBox(css_container)), NGOutOfFlowLayoutPart(NGBlockNode(ToLayoutBox(css_container)),
*constraint_space, *container_style, &container_builder) *constraint_space, *container_style, &container_builder)
.Run(); .Run(/* update_legacy */ false);
RefPtr<NGLayoutResult> result = container_builder.ToBoxFragment(); RefPtr<NGLayoutResult> result = container_builder.ToBoxFragment();
// These are the OOF descendants of the current OOF block. // These are the unpositioned OOF descendants of the current OOF block.
for (NGOutOfFlowPositionedDescendant descendant : for (NGOutOfFlowPositionedDescendant descendant :
result->OutOfFlowPositionedDescendants()) result->OutOfFlowPositionedDescendants())
descendant.node.UseOldOutOfFlowPositioning(); descendant.node.UseOldOutOfFlowPositioning();
...@@ -326,6 +336,10 @@ void LayoutNGBlockFlow::SetCachedLayoutResult( ...@@ -326,6 +336,10 @@ void LayoutNGBlockFlow::SetCachedLayoutResult(
cached_result_ = layout_result; cached_result_ = layout_result;
} }
RefPtr<NGLayoutResult> LayoutNGBlockFlow::CachedLayoutResultForTesting() {
return cached_result_;
}
void LayoutNGBlockFlow::SetPaintFragment( void LayoutNGBlockFlow::SetPaintFragment(
RefPtr<const NGPhysicalFragment> fragment) { RefPtr<const NGPhysicalFragment> fragment) {
paint_fragment_ = WTF::MakeUnique<NGPaintFragment>(std::move(fragment)); paint_fragment_ = WTF::MakeUnique<NGPaintFragment>(std::move(fragment));
......
...@@ -55,6 +55,8 @@ class CORE_EXPORT LayoutNGBlockFlow : public LayoutBlockFlow { ...@@ -55,6 +55,8 @@ class CORE_EXPORT LayoutNGBlockFlow : public LayoutBlockFlow {
void SetCachedLayoutResult(const NGConstraintSpace&, void SetCachedLayoutResult(const NGConstraintSpace&,
NGBreakToken*, NGBreakToken*,
RefPtr<NGLayoutResult>); RefPtr<NGLayoutResult>);
// For testing only.
RefPtr<NGLayoutResult> CachedLayoutResultForTesting();
NGPaintFragment* PaintFragment() const { return paint_fragment_.get(); } NGPaintFragment* PaintFragment() const { return paint_fragment_.get(); }
void SetPaintFragment(RefPtr<const NGPhysicalFragment>); void SetPaintFragment(RefPtr<const NGPhysicalFragment>);
......
...@@ -709,9 +709,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) { ...@@ -709,9 +709,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
<div id="inflow"></div> <div id="inflow"></div>
)HTML"); )HTML");
const NGPhysicalBoxFragment* zero; const LayoutNGBlockFlow* zero;
const NGPhysicalBoxFragment* abs; const LayoutNGBlockFlow* abs;
const NGPhysicalBoxFragment* inflow; const LayoutNGBlockFlow* inflow;
RefPtr<const NGPhysicalBoxFragment> fragment; RefPtr<const NGPhysicalBoxFragment> fragment;
auto run_test = [&](const Length& zero_top_margin_bottom, auto run_test = [&](const Length& zero_top_margin_bottom,
const Length& zero_inner_margin_top, const Length& zero_inner_margin_top,
...@@ -721,36 +721,36 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) { ...@@ -721,36 +721,36 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
// Set the style of the elements we care about. // Set the style of the elements we care about.
Element* zero_top = GetDocument().getElementById("zero-top"); Element* zero_top = GetDocument().getElementById("zero-top");
zero_top->MutableComputedStyle()->SetMarginBottom(zero_top_margin_bottom); zero_top->MutableComputedStyle()->SetMarginBottom(zero_top_margin_bottom);
zero_top->GetLayoutObject()->SetNeedsLayout("");
Element* zero_inner = GetDocument().getElementById("zero-inner"); Element* zero_inner = GetDocument().getElementById("zero-inner");
zero_inner->MutableComputedStyle()->SetMarginTop(zero_inner_margin_top); zero_inner->MutableComputedStyle()->SetMarginTop(zero_inner_margin_top);
zero_inner->MutableComputedStyle()->SetMarginBottom( zero_inner->MutableComputedStyle()->SetMarginBottom(
zero_inner_margin_bottom); zero_inner_margin_bottom);
zero_inner->GetLayoutObject()->SetNeedsLayout("");
Element* zero_element = GetDocument().getElementById("zero"); Element* zero_element = GetDocument().getElementById("zero");
zero_element->MutableComputedStyle()->SetMarginBottom(zero_margin_bottom); zero_element->MutableComputedStyle()->SetMarginBottom(zero_margin_bottom);
zero_element->GetLayoutObject()->SetNeedsLayout("");
Element* inflow_element = GetDocument().getElementById("inflow"); Element* inflow_element = GetDocument().getElementById("inflow");
inflow_element->MutableComputedStyle()->SetMarginTop(inflow_margin_top); inflow_element->MutableComputedStyle()->SetMarginTop(inflow_margin_top);
inflow_element->GetLayoutObject()->SetNeedsLayout("");
std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement( GetDocument().View()->UpdateAllLifecyclePhases();
GetDocument().getElementsByTagName("html")->item(0));
FragmentChildIterator iterator(fragment.get());
// body
const NGPhysicalBoxFragment* child = iterator.NextChild();
LayoutNGBlockFlow* child;
// #float // #float
iterator.SetParent(child); child = ToLayoutNGBlockFlow(
child = iterator.NextChild(); GetDocument().getElementById("float")->GetLayoutObject());
EXPECT_EQ(NGPhysicalSize(LayoutUnit(50), LayoutUnit(50)), child->Size()); EXPECT_EQ(LayoutSize(LayoutUnit(50), LayoutUnit(50)), child->Size());
EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(0)), child->Offset()); EXPECT_EQ(LayoutPoint(LayoutUnit(0), LayoutUnit(0)), child->Location());
// We need to manually test the position of #zero, #abs, #inflow. // We need to manually test the position of #zero, #abs, #inflow.
iterator.NextChild(); // #zero-top. zero = ToLayoutNGBlockFlow(
zero = iterator.NextChild(); GetDocument().getElementById("zero")->GetLayoutObject());
inflow = iterator.NextChild(); // NOTE: Layout reordered the fragments. inflow = ToLayoutNGBlockFlow(
abs = iterator.NextChild(); GetDocument().getElementById("inflow")->GetLayoutObject());
abs = ToLayoutNGBlockFlow(
GetDocument().getElementById("abs")->GetLayoutObject());
}; };
// Base case of no margins. // Base case of no margins.
...@@ -762,9 +762,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) { ...@@ -762,9 +762,9 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
/* #inflow margin-top */ Length(0, kFixed)); /* #inflow margin-top */ Length(0, kFixed));
// #zero, #abs, #inflow should all be positioned at the float. // #zero, #abs, #inflow should all be positioned at the float.
EXPECT_EQ(LayoutUnit(50), zero->Offset().top); EXPECT_EQ(LayoutUnit(50), zero->Location().Y());
EXPECT_EQ(LayoutUnit(50), abs->Offset().top); EXPECT_EQ(LayoutUnit(50), abs->Location().Y());
EXPECT_EQ(LayoutUnit(50), inflow->Offset().top); EXPECT_EQ(LayoutUnit(50), inflow->Location().Y());
// A margin strut which resolves to -50 (-70 + 20) adjusts the position of // A margin strut which resolves to -50 (-70 + 20) adjusts the position of
// #zero to the float clearance. // #zero to the float clearance.
...@@ -777,15 +777,15 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) { ...@@ -777,15 +777,15 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
// #zero is placed at the float, the margin strut is at: // #zero is placed at the float, the margin strut is at:
// 90 = (50 - (-60 + 20)). // 90 = (50 - (-60 + 20)).
EXPECT_EQ(LayoutUnit(50), zero->Offset().top); EXPECT_EQ(LayoutUnit(50), zero->Location().Y());
// #abs estimates its position with the margin strut: // #abs estimates its position with the margin strut:
// 40 = (90 + (-70 + 20)). // 40 = (90 + (-70 + 20)).
EXPECT_EQ(LayoutUnit(40), abs->Offset().top); EXPECT_EQ(LayoutUnit(40), abs->Location().Y());
// #inflow has similar behaviour to #abs, but includes its margin. // #inflow has similar behaviour to #abs, but includes its margin.
// 70 = (90 + (-70 + 50)) // 70 = (90 + (-70 + 50))
EXPECT_EQ(LayoutUnit(70), inflow->Offset().top); EXPECT_EQ(LayoutUnit(70), inflow->Location().Y());
// A margin strut which resolves to 60 (-10 + 70) means that #zero doesn't // A margin strut which resolves to 60 (-10 + 70) means that #zero doesn't
// get adjusted to clear the float, and we have normal behaviour. // get adjusted to clear the float, and we have normal behaviour.
...@@ -800,15 +800,15 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) { ...@@ -800,15 +800,15 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
/* #inflow margin-top */ Length(80, kFixed)); /* #inflow margin-top */ Length(80, kFixed));
// #zero is placed at 60 (-10 + 70). // #zero is placed at 60 (-10 + 70).
EXPECT_EQ(LayoutUnit(60), zero->Offset().top); EXPECT_EQ(LayoutUnit(60), zero->Location().Y());
// #abs estimates its position with the margin strut: // #abs estimates its position with the margin strut:
// 50 = (0 + (-20 + 70)). // 50 = (0 + (-20 + 70)).
EXPECT_EQ(LayoutUnit(50), abs->Offset().top); EXPECT_EQ(LayoutUnit(50), abs->Location().Y());
// #inflow has similar behaviour to #abs, but includes its margin. // #inflow has similar behaviour to #abs, but includes its margin.
// 60 = (0 + (-20 + 80)) // 60 = (0 + (-20 + 80))
EXPECT_EQ(LayoutUnit(60), inflow->Offset().top); EXPECT_EQ(LayoutUnit(60), inflow->Location().Y());
// #zero-top produces a margin which needs to be ignored, as #zero is // #zero-top produces a margin which needs to be ignored, as #zero is
// affected by clearance, it needs to have layout performed again, starting // affected by clearance, it needs to have layout performed again, starting
...@@ -822,11 +822,11 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) { ...@@ -822,11 +822,11 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
// #zero is placed at the float, the margin strut is at: // #zero is placed at the float, the margin strut is at:
// 40 = (50 - (-10 + 20)). // 40 = (50 - (-10 + 20)).
EXPECT_EQ(LayoutUnit(50), zero->Offset().top); EXPECT_EQ(LayoutUnit(50), zero->Location().Y());
// The margin strut is now disjoint, this is placed at: // The margin strut is now disjoint, this is placed at:
// 55 = (40 + (-10 + 25)) // 55 = (40 + (-10 + 25))
EXPECT_EQ(LayoutUnit(55), inflow->Offset().top); EXPECT_EQ(LayoutUnit(55), inflow->Location().Y());
} }
// Tests that when auto margins are applied to a new formatting context, they // Tests that when auto margins are applied to a new formatting context, they
......
...@@ -340,7 +340,7 @@ void NGBlockNode::CopyFragmentDataToLayoutBox( ...@@ -340,7 +340,7 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
intrinsic_block_size += intrinsic_block_size +=
PreviouslyUsedBlockSpace(constraint_space, physical_fragment); PreviouslyUsedBlockSpace(constraint_space, physical_fragment);
} }
block->LayoutPositionedObjects(true); block->LayoutPositionedObjects(/* relayout_children */ false);
if (flow_thread) { if (flow_thread) {
UpdateLegacyMultiColumnFlowThread(*this, flow_thread, constraint_space, UpdateLegacyMultiColumnFlowThread(*this, flow_thread, constraint_space,
......
...@@ -46,7 +46,7 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart( ...@@ -46,7 +46,7 @@ NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
icb_size_ = container_space.InitialContainingBlockSize(); icb_size_ = container_space.InitialContainingBlockSize();
} }
void NGOutOfFlowLayoutPart::Run() { void NGOutOfFlowLayoutPart::Run(bool update_legacy) {
Vector<NGOutOfFlowPositionedDescendant> descendant_candidates; Vector<NGOutOfFlowPositionedDescendant> descendant_candidates;
container_builder_->GetAndClearOutOfFlowDescendantCandidates( container_builder_->GetAndClearOutOfFlowDescendantCandidates(
&descendant_candidates); &descendant_candidates);
...@@ -58,6 +58,8 @@ void NGOutOfFlowLayoutPart::Run() { ...@@ -58,6 +58,8 @@ void NGOutOfFlowLayoutPart::Run() {
RefPtr<NGLayoutResult> result = LayoutDescendant( RefPtr<NGLayoutResult> result = LayoutDescendant(
candidate.node, candidate.static_position, &offset); candidate.node, candidate.static_position, &offset);
container_builder_->AddChild(std::move(result), offset); container_builder_->AddChild(std::move(result), offset);
if (update_legacy)
candidate.node.UseOldOutOfFlowPositioning();
} else { } else {
container_builder_->AddOutOfFlowDescendant(candidate); container_builder_->AddOutOfFlowDescendant(candidate);
} }
......
...@@ -31,7 +31,10 @@ class CORE_EXPORT NGOutOfFlowLayoutPart { ...@@ -31,7 +31,10 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
const NGConstraintSpace& container_space, const NGConstraintSpace& container_space,
const ComputedStyle& container_style, const ComputedStyle& container_style,
NGFragmentBuilder* container_builder); NGFragmentBuilder* container_builder);
void Run();
// update_legacy will place NG OOF descendants into their Legacy container.
// It should be false if OOF descendants have already been placed into Legacy.
void Run(bool update_legacy = true);
private: private:
RefPtr<NGLayoutResult> LayoutDescendant(NGBlockNode descendant, RefPtr<NGLayoutResult> LayoutDescendant(NGBlockNode descendant,
......
...@@ -15,9 +15,11 @@ class NGOutOfFlowLayoutPartTest : public RenderingTest { ...@@ -15,9 +15,11 @@ class NGOutOfFlowLayoutPartTest : public RenderingTest {
public: public:
NGOutOfFlowLayoutPartTest() { NGOutOfFlowLayoutPartTest() {
RuntimeEnabledFeatures::SetLayoutNGEnabled(true); RuntimeEnabledFeatures::SetLayoutNGEnabled(true);
RuntimeEnabledFeatures::SetLayoutNGFragmentCachingEnabled(true);
}; };
~NGOutOfFlowLayoutPartTest() { ~NGOutOfFlowLayoutPartTest() {
RuntimeEnabledFeatures::SetLayoutNGEnabled(false); RuntimeEnabledFeatures::SetLayoutNGEnabled(false);
RuntimeEnabledFeatures::SetLayoutNGFragmentCachingEnabled(false);
}; };
}; };
...@@ -67,8 +69,8 @@ TEST_F(NGOutOfFlowLayoutPartTest, FixedInsideAbs) { ...@@ -67,8 +69,8 @@ TEST_F(NGOutOfFlowLayoutPartTest, FixedInsideAbs) {
LayoutNGBlockFlow* block_flow = ToLayoutNGBlockFlow(rel->GetLayoutObject()); LayoutNGBlockFlow* block_flow = ToLayoutNGBlockFlow(rel->GetLayoutObject());
RefPtr<NGConstraintSpace> space = RefPtr<NGConstraintSpace> space =
NGConstraintSpace::CreateFromLayoutObject(*block_flow); NGConstraintSpace::CreateFromLayoutObject(*block_flow);
NGBlockNode node(block_flow); RefPtr<NGLayoutResult> result = block_flow->CachedLayoutResultForTesting();
RefPtr<NGLayoutResult> result = node.Layout(*space); EXPECT_TRUE(result);
EXPECT_EQ(result->OutOfFlowPositionedDescendants().size(), (size_t)2); EXPECT_EQ(result->OutOfFlowPositionedDescendants().size(), (size_t)2);
// Test the final result. // Test the final result.
...@@ -80,83 +82,6 @@ TEST_F(NGOutOfFlowLayoutPartTest, FixedInsideAbs) { ...@@ -80,83 +82,6 @@ TEST_F(NGOutOfFlowLayoutPartTest, FixedInsideAbs) {
EXPECT_EQ(fixed_2->OffsetTop(), LayoutUnit(9)); EXPECT_EQ(fixed_2->OffsetTop(), LayoutUnit(9));
}; };
TEST_F(NGOutOfFlowLayoutPartTest, OrthogonalWritingMode1) {
SetBodyInnerHTML(
R"HTML(
<style>
#container {
position: relative;
writing-mode: horizontal-tb;
width: 200px;
height: 400px;
}
#abs-child {
position: absolute;
top: 10px;
writing-mode: vertical-rl;
width: auto;
height: 30px;
}
</style>
<div id="container">
<div id="abs-child"></div>
</div>
)HTML");
LayoutNGBlockFlow* block_flow =
ToLayoutNGBlockFlow(GetLayoutObjectByElementId("container"));
NGBlockNode node(block_flow);
RefPtr<NGConstraintSpace> space =
NGConstraintSpace::CreateFromLayoutObject(*block_flow);
RefPtr<const NGPhysicalFragment> fragment =
node.Layout(*space)->PhysicalFragment();
EXPECT_EQ(NGPhysicalSize(LayoutUnit(200), LayoutUnit(400)), fragment->Size());
fragment = ToNGPhysicalBoxFragment(fragment.get())->Children()[0];
EXPECT_EQ(NGPhysicalSize(LayoutUnit(0), LayoutUnit(30)), fragment->Size());
EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(10)),
fragment->Offset());
};
TEST_F(NGOutOfFlowLayoutPartTest, OrthogonalWritingMode2) {
SetBodyInnerHTML(
R"HTML(
<style>
#container {
position: relative;
writing-mode: horizontal-tb;
width: 200px;
height: 400px;
}
#abs-child {
position: absolute;
top: 10px;
writing-mode: vertical-rl;
width: 20%;
height: 30px;
}
</style>
<div id="container">
<div id="abs-child"></div>
</div>
)HTML");
LayoutNGBlockFlow* block_flow =
ToLayoutNGBlockFlow(GetLayoutObjectByElementId("container"));
NGBlockNode node(block_flow);
RefPtr<NGConstraintSpace> space =
NGConstraintSpace::CreateFromLayoutObject(*block_flow);
RefPtr<const NGPhysicalFragment> fragment =
node.Layout(*space)->PhysicalFragment();
EXPECT_EQ(NGPhysicalSize(LayoutUnit(200), LayoutUnit(400)), fragment->Size());
fragment = ToNGPhysicalBoxFragment(fragment.get())->Children()[0];
EXPECT_EQ(NGPhysicalSize(LayoutUnit(40), LayoutUnit(30)), fragment->Size());
EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(10)),
fragment->Offset());
};
} // namespace } // namespace
} // namespace blink } // namespace blink
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