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(
NGLineBoxFragmentBuilder::ChildList* line_box,
FontBaseline baseline_type) {
DCHECK(box->needs_box_fragment);
// The inline box should have the height of the font metrics without the
// line-height property. Compute from style because |box->metrics| includes
// the line-height property.
DCHECK(box->style);
const ComputedStyle& style = *box->style;
NGLineHeightMetrics metrics(style, baseline_type);
// Extend the block direction of the box by borders and paddings. Inline
// direction is already included into positions in NGLineBreaker.
NGLogicalOffset offset(
LayoutUnit(),
-metrics.ascent - (box->borders.line_over + box->padding.line_over));
NGLogicalSize size(
LayoutUnit(),
metrics.LineHeight() + box->borders.BlockSum() + box->padding.BlockSum());
NGLogicalOffset offset;
NGLogicalSize size;
if (!is_empty_line_) {
// The inline box should have the height of the font metrics without the
// line-height property. Compute from style because |box->metrics| includes
// the line-height property.
NGLineHeightMetrics metrics(style, baseline_type);
// Extend the block direction of the box by borders and paddings. Inline
// direction is already included into positions in NGLineBreaker.
offset.block_offset =
-metrics.ascent - (box->borders.line_over + box->padding.line_over);
size.block_size = metrics.LineHeight() + box->borders.BlockSum() +
box->padding.BlockSum();
}
unsigned fragment_end = line_box->size();
DCHECK(box->item);
......
......@@ -114,6 +114,8 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// The box state for the line box.
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.
// @return The initial box state for the line.
NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle*, FontBaseline, bool);
......@@ -246,6 +248,8 @@ class CORE_EXPORT NGInlineLayoutStateStack {
Vector<NGInlineBoxState, 4> stack_;
Vector<BoxData, 4> box_data_list_;
bool is_empty_line_ = false;
};
} // namespace blink
......
......@@ -239,6 +239,7 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
// 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.
box_states_->SetIsEmptyLine(line_info->IsEmptyLine());
NGInlineBoxState* box =
box_states_->OnBeginPlaceItems(&line_style, baseline_type_, quirks_mode_);
#if DCHECK_IS_ON()
......@@ -359,6 +360,7 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
// shouldn't trigger creation of a line. Exit now if that's the case.
if (line_info->IsEmptyLine()) {
container_builder_.SetIsEmptyLineBox();
container_builder_.AddChildren(line_box_);
return;
}
......
......@@ -126,6 +126,51 @@ TEST_F(NGInlineLayoutAlgorithmTest, GenerateEllipsis) {
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
// fragments for a wrapped line, it should consistently do so for other lines
// too, when the inline box is fragmented to multiple lines.
......
......@@ -83,11 +83,6 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
}
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_);
if (!break_token_)
......
......@@ -191,6 +191,10 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
}
LayoutSize corrected_offset = additional_offset - first_fragment_offset;
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))
block_for_flipping->FlipForWritingMode(outline);
outline.Move(corrected_offset);
......
......@@ -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/889721 fast/inline/continuation-outlines-with-layers.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/591099 fast/overflow/overflow-update-transform.html [ Failure ]
crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
......@@ -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/lazy-loaded-style.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/compositing/subpixel-offset-scaled-transform-composited.html [ Failure ]
crbug.com/591099 paint/invalidation/crbug-371640-4.html [ Failure ]
......
......@@ -20,12 +20,12 @@
{
"object": "NGPhysicalBoxFragment LayoutInline SPAN",
"rect": [7, 7, 102, 106],
"reason": "geometry"
"reason": "outline"
},
{
"object": "NGPhysicalBoxFragment LayoutInline SPAN",
"rect": [7, 87, 102, 102],
"reason": "geometry"
"reason": "outline"
},
{
"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