Commit 744ec324 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[LayoutNG] Create fragments in "empty" line boxes

The "empty" line box is what CSS defines as "certain zero-
height line box", that suffices certain conditions as defined
in the spec and is ignored for margin collapsing.

It has some special behaviors, such as to ignore strut, that
LayoutNG suppressed to generate their child fragments.
However, we need them under certain conditions such as when
they have out-of-flow container as descendants.

This change breaks some normal flow, out-of-flow, and outline
tests.

Normal flow failures were fixed by adding an explicit
|IsEmptyLineBox()| function.

Out-of-flow failures are fixed as a separate CL in r610994
(CL:1351189).

Outline failures are fixed in this CL and in r611954
(CL:13543199) thanks to atotic@.

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I4d393af016439cdbe085d91fdd1e8550d320d1f1
Bug: 636993, 903578
Reviewed-on: https://chromium-review.googlesource.com/c/1251142
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarAleks Totic <atotic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612108}
parent e5d0b088
...@@ -270,22 +270,24 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder( ...@@ -270,22 +270,24 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
NGLineBoxFragmentBuilder::ChildList* line_box, NGLineBoxFragmentBuilder::ChildList* line_box,
FontBaseline baseline_type) { FontBaseline baseline_type) {
DCHECK(box->needs_box_fragment); DCHECK(box->needs_box_fragment);
DCHECK(box->style);
const ComputedStyle& style = *box->style;
NGLogicalOffset offset;
NGLogicalSize size;
if (!is_empty_line_) {
// The inline box should have the height of the font metrics without the // The inline box should have the height of the font metrics without the
// line-height property. Compute from style because |box->metrics| includes // line-height property. Compute from style because |box->metrics| includes
// the line-height property. // the line-height property.
DCHECK(box->style);
const ComputedStyle& style = *box->style;
NGLineHeightMetrics metrics(style, baseline_type); NGLineHeightMetrics metrics(style, baseline_type);
// Extend the block direction of the box by borders and paddings. Inline // Extend the block direction of the box by borders and paddings. Inline
// direction is already included into positions in NGLineBreaker. // direction is already included into positions in NGLineBreaker.
NGLogicalOffset offset( offset.block_offset =
LayoutUnit(), -metrics.ascent - (box->borders.line_over + box->padding.line_over);
-metrics.ascent - (box->borders.line_over + box->padding.line_over)); size.block_size = metrics.LineHeight() + box->borders.BlockSum() +
NGLogicalSize size( box->padding.BlockSum();
LayoutUnit(), }
metrics.LineHeight() + box->borders.BlockSum() + box->padding.BlockSum());
unsigned fragment_end = line_box->size(); unsigned fragment_end = line_box->size();
DCHECK(box->item); DCHECK(box->item);
......
...@@ -114,6 +114,8 @@ class CORE_EXPORT NGInlineLayoutStateStack { ...@@ -114,6 +114,8 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// The box state for the line box. // The box state for the line box.
NGInlineBoxState& LineBoxState() { return stack_.front(); } NGInlineBoxState& LineBoxState() { return stack_.front(); }
void SetIsEmptyLine(bool is_empty_line) { is_empty_line_ = is_empty_line; }
// Initialize the box state stack for a new line. // Initialize the box state stack for a new line.
// @return The initial box state for the line. // @return The initial box state for the line.
NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle*, FontBaseline, bool); NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle*, FontBaseline, bool);
...@@ -246,6 +248,8 @@ class CORE_EXPORT NGInlineLayoutStateStack { ...@@ -246,6 +248,8 @@ class CORE_EXPORT NGInlineLayoutStateStack {
Vector<NGInlineBoxState, 4> stack_; Vector<NGInlineBoxState, 4> stack_;
Vector<BoxData, 4> box_data_list_; Vector<BoxData, 4> box_data_list_;
bool is_empty_line_ = false;
}; };
} // namespace blink } // namespace blink
......
...@@ -239,6 +239,7 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info, ...@@ -239,6 +239,7 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
// Compute heights of all inline items by placing the dominant baseline at 0. // Compute heights of all inline items by placing the dominant baseline at 0.
// The baseline is adjusted after the height of the line box is computed. // The baseline is adjusted after the height of the line box is computed.
box_states_->SetIsEmptyLine(line_info->IsEmptyLine());
NGInlineBoxState* box = NGInlineBoxState* box =
box_states_->OnBeginPlaceItems(&line_style, baseline_type_, quirks_mode_); box_states_->OnBeginPlaceItems(&line_style, baseline_type_, quirks_mode_);
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
...@@ -359,6 +360,7 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info, ...@@ -359,6 +360,7 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
// shouldn't trigger creation of a line. Exit now if that's the case. // shouldn't trigger creation of a line. Exit now if that's the case.
if (line_info->IsEmptyLine()) { if (line_info->IsEmptyLine()) {
container_builder_.SetIsEmptyLineBox(); container_builder_.SetIsEmptyLineBox();
container_builder_.AddChildren(line_box_);
return; return;
} }
......
...@@ -126,6 +126,51 @@ TEST_F(NGInlineLayoutAlgorithmTest, GenerateEllipsis) { ...@@ -126,6 +126,51 @@ TEST_F(NGInlineLayoutAlgorithmTest, GenerateEllipsis) {
EXPECT_EQ(line1.Children()[0]->GetLayoutObject(), ellipsis.GetLayoutObject()); EXPECT_EQ(line1.Children()[0]->GetLayoutObject(), ellipsis.GetLayoutObject());
} }
// This test ensures box fragments are generated when necessary, even when the
// line is empty. One such case is when the line contains a containing box of an
// out-of-flow object.
TEST_F(NGInlineLayoutAlgorithmTest,
EmptyLineWithOutOfFlowInInlineContainingBlock) {
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style>
oof-container {
position: relative;
}
oof {
position: absolute;
width: 100px;
height: 100px;
}
html, body { margin: 0; }
html {
font-size: 10px;
}
</style>
<div id=container>
<oof-container>
<oof></oof>
</oof-container>
</div>
)HTML");
LayoutBlockFlow* block_flow =
ToLayoutBlockFlow(GetLayoutObjectByElementId("container"));
const NGPhysicalBoxFragment* container = block_flow->CurrentFragment();
ASSERT_TRUE(container);
EXPECT_EQ(LayoutUnit(), container->Size().height);
EXPECT_EQ(2u, container->Children().size());
const NGPhysicalLineBoxFragment& linebox =
ToNGPhysicalLineBoxFragment(*container->Children()[0]);
EXPECT_EQ(1u, linebox.Children().size());
EXPECT_EQ(NGPhysicalSize(), linebox.Size());
const NGPhysicalBoxFragment& oof_container =
ToNGPhysicalBoxFragment(*linebox.Children()[0]);
EXPECT_EQ(NGPhysicalSize(), oof_container.Size());
}
// This test ensures that if an inline box generates (or does not generate) box // This test ensures that if an inline box generates (or does not generate) box
// fragments for a wrapped line, it should consistently do so for other lines // fragments for a wrapped line, it should consistently do so for other lines
// too, when the inline box is fragmented to multiple lines. // too, when the inline box is fragmented to multiple lines.
......
...@@ -83,11 +83,6 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) { ...@@ -83,11 +83,6 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
} }
scoped_refptr<NGLayoutResult> NGLineBoxFragmentBuilder::ToLineBoxFragment() { scoped_refptr<NGLayoutResult> NGLineBoxFragmentBuilder::ToLineBoxFragment() {
#if DCHECK_IS_ON()
if (line_box_type_ == NGPhysicalLineBoxFragment::kEmptyLineBox)
DCHECK_EQ(children_.size(), 0u);
#endif
writing_mode_ = ToLineWritingMode(writing_mode_); writing_mode_ = ToLineWritingMode(writing_mode_);
if (!break_token_) if (!break_token_)
......
...@@ -191,6 +191,10 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects( ...@@ -191,6 +191,10 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
} }
LayoutSize corrected_offset = additional_offset - first_fragment_offset; LayoutSize corrected_offset = additional_offset - first_fragment_offset;
for (auto& outline : blockflow_outline_rects) { for (auto& outline : blockflow_outline_rects) {
// Skip if both width and height are zero. Contaning blocks in empty
// linebox is one such case.
if (outline.Size().IsZero())
continue;
if (UNLIKELY(block_for_flipping)) if (UNLIKELY(block_for_flipping))
block_for_flipping->FlipForWritingMode(outline); block_for_flipping->FlipForWritingMode(outline);
outline.Move(corrected_offset); outline.Move(corrected_offset);
......
...@@ -287,7 +287,6 @@ crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pas ...@@ -287,7 +287,6 @@ crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pas
crbug.com/591099 fast/forms/textarea/basic-textareas-quirks.html [ Failure ] crbug.com/591099 fast/forms/textarea/basic-textareas-quirks.html [ Failure ]
crbug.com/889721 fast/inline/continuation-outlines-with-layers.html [ Failure ] crbug.com/889721 fast/inline/continuation-outlines-with-layers.html [ Failure ]
crbug.com/889721 fast/inline/continuation-outlines.html [ Failure ] crbug.com/889721 fast/inline/continuation-outlines.html [ Failure ]
crbug.com/835484 fast/inline/inline-focus-ring-under-absolute-enclosing-relative-div.html [ Failure ]
crbug.com/889721 fast/inline/outline-continuations.html [ Failure ] crbug.com/889721 fast/inline/outline-continuations.html [ Failure ]
crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ] crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ] crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
...@@ -317,7 +316,6 @@ crbug.com/591099 intersection-observer/v2/text-shadow.html [ Failure ] ...@@ -317,7 +316,6 @@ crbug.com/591099 intersection-observer/v2/text-shadow.html [ Failure ]
crbug.com/591099 media/controls/buttons-after-reset.html [ Failure Pass ] crbug.com/591099 media/controls/buttons-after-reset.html [ Failure Pass ]
crbug.com/591099 media/controls/lazy-loaded-style.html [ Failure ] crbug.com/591099 media/controls/lazy-loaded-style.html [ Failure ]
crbug.com/591099 paint/float/float-under-inline-self-painting-change.html [ Failure ] crbug.com/591099 paint/float/float-under-inline-self-painting-change.html [ Failure ]
crbug.com/835484 paint/inline/focus-ring-under-absolute-with-relative-continuation.html [ Failure ]
crbug.com/591099 paint/invalidation/clip/clip-with-layout-delta.html [ Failure ] crbug.com/591099 paint/invalidation/clip/clip-with-layout-delta.html [ Failure ]
crbug.com/591099 paint/invalidation/compositing/subpixel-offset-scaled-transform-composited.html [ Failure ] crbug.com/591099 paint/invalidation/compositing/subpixel-offset-scaled-transform-composited.html [ Failure ]
crbug.com/591099 paint/invalidation/crbug-371640-4.html [ Failure ] crbug.com/591099 paint/invalidation/crbug-371640-4.html [ Failure ]
......
...@@ -20,12 +20,12 @@ ...@@ -20,12 +20,12 @@
{ {
"object": "NGPhysicalBoxFragment LayoutInline SPAN", "object": "NGPhysicalBoxFragment LayoutInline SPAN",
"rect": [7, 7, 102, 106], "rect": [7, 7, 102, 106],
"reason": "geometry" "reason": "outline"
}, },
{ {
"object": "NGPhysicalBoxFragment LayoutInline SPAN", "object": "NGPhysicalBoxFragment LayoutInline SPAN",
"rect": [7, 87, 102, 102], "rect": [7, 87, 102, 102],
"reason": "geometry" "reason": "outline"
}, },
{ {
"object": "LayoutNGBlockFlow (relative positioned) DIV id='block'", "object": "LayoutNGBlockFlow (relative positioned) DIV id='block'",
......
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