Commit c1a7d15a authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Multicol baseline propagation support.

Spec: https://drafts.csswg.org/css-align/#baseline-export

The "first baseline set" of a multicol container is the baseline of the
first line box in the first column (i,e, ignore all other columns), or
the baseline of the first line box in the first column spanner that has
such a thing, whichever comes first.

Multicol containers have no "last baseline set", and, as such,
fast/multicol/inline-block-baseline.html is invalid, since an
inline-block aligns with the "last baseline set". Remove the test, and
replace it with its antithesis, baseline-008.html in
wpt/css/css-multicol/.

And added a bunch of tests, since this feature seemed to have no
coverage, apart from the deleted test in fast/multicol/.

Bug: 829028
Change-Id: I954de9618fde87dbfa37292786ca6a2dcce9fa1f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2421462Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810140}
parent cf14b24b
......@@ -282,8 +282,6 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
if (const auto* token = BreakToken())
previously_consumed_block_size = token->ConsumedBlockSize();
// TODO(mstensho): Propagate baselines.
// Save the unconstrained intrinsic size on the builder before clamping it.
container_builder_.SetOverflowBlockSize(intrinsic_block_size_);
......@@ -710,8 +708,6 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
column_size.block_size = new_column_block_size;
} while (true);
intrinsic_block_size_ += column_size.block_size;
// If we just have one empty fragmentainer, we need to keep the trailing
// margin from any previous column spanner, and also make sure that we don't
// incorrectly consider this to be a class A breakpoint. A fragmentainer may
......@@ -723,8 +719,20 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
if (!is_empty) {
has_processed_first_child_ = true;
container_builder_.SetPreviousBreakAfter(EBreakBetween::kAuto);
if (!has_processed_first_column_) {
has_processed_first_column_ = true;
// According to the spec, we should only look for a baseline in the first
// column.
const auto& first_column =
To<NGPhysicalBoxFragment>(new_columns[0].Fragment());
PropagateBaselineFromChild(first_column, intrinsic_block_size_);
}
}
intrinsic_block_size_ += column_size.block_size;
// Commit all column fragments to the fragment builder.
const NGBlockBreakToken* incoming_column_token = next_column_token;
for (auto result_with_offset : new_columns) {
......@@ -788,21 +796,28 @@ NGBreakStatus NGColumnLayoutAlgorithm::LayoutSpanner(
}
}
NGFragment fragment(ConstraintSpace().GetWritingMode(),
result->PhysicalFragment());
const auto& spanner_fragment =
To<NGPhysicalBoxFragment>(result->PhysicalFragment());
NGFragment logical_fragment(ConstraintSpace().GetWritingMode(),
spanner_fragment);
ResolveInlineMargins(spanner_style, Style(), ChildAvailableSize().inline_size,
fragment.InlineSize(), &margins);
logical_fragment.InlineSize(), &margins);
LogicalOffset offset(
BorderScrollbarPadding().inline_start + margins.inline_start,
block_offset);
container_builder_.AddResult(*result, offset);
// According to the spec, the first spanner that has a baseline contributes
// with its baseline to the multicol container. This is in contrast to column
// content, where only the first column may contribute with a baseline.
PropagateBaselineFromChild(spanner_fragment, offset.block_offset);
*margin_strut = NGMarginStrut();
margin_strut->Append(margins.block_end, /* is_quirky */ false);
intrinsic_block_size_ = offset.block_offset + fragment.BlockSize();
intrinsic_block_size_ = offset.block_offset + logical_fragment.BlockSize();
has_processed_first_child_ = true;
EBreakBetween break_after = JoinFragmentainerBreakValues(
......@@ -812,6 +827,26 @@ NGBreakStatus NGColumnLayoutAlgorithm::LayoutSpanner(
return NGBreakStatus::kContinue;
}
void NGColumnLayoutAlgorithm::PropagateBaselineFromChild(
const NGPhysicalBoxFragment& child,
LayoutUnit block_offset) {
// Bail if a baseline was already found.
if (container_builder_.Baseline())
return;
// According to the spec, multicol containers have no "last baseline set", so,
// unless we're looking for a "first baseline set", we have no work to do.
if (ConstraintSpace().BaselineAlgorithmType() !=
NGBaselineAlgorithmType::kFirstLine)
return;
NGBoxFragment logical_fragment(ConstraintSpace().GetWritingMode(),
ConstraintSpace().Direction(), child);
if (auto baseline = logical_fragment.FirstBaseline())
container_builder_.SetBaseline(block_offset + *baseline);
}
LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
const LogicalSize& column_size,
const NGBlockBreakToken* child_break_token) {
......@@ -1030,6 +1065,10 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForSpanner(
space_builder.SetAvailableSize(ChildAvailableSize());
space_builder.SetPercentageResolutionSize(ChildAvailableSize());
space_builder.SetNeedsBaseline(ConstraintSpace().NeedsBaseline());
space_builder.SetBaselineAlgorithmType(
ConstraintSpace().BaselineAlgorithmType());
if (ConstraintSpace().HasBlockFragmentation()) {
SetupSpaceBuilderForFragmentation(ConstraintSpace(), spanner, block_offset,
&space_builder, /* is_new_fc */ true);
......
......@@ -52,6 +52,10 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
const NGBlockBreakToken* break_token,
NGMarginStrut*);
// Propagate the baseline from the given |child| if needed.
void PropagateBaselineFromChild(const NGPhysicalBoxFragment& child,
LayoutUnit block_offset);
LayoutUnit CalculateBalancedColumnBlockSize(
const LogicalSize& column_size,
const NGBlockBreakToken* child_break_token);
......@@ -102,6 +106,8 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
// the first piece of content of the multicol container. It is used to check
// if we're at a valid class A breakpoint (between block-level siblings).
bool has_processed_first_child_ = false;
bool has_processed_first_column_ = false;
};
} // namespace blink
......
......@@ -710,6 +710,9 @@ NGConstraintSpace CreateConstraintSpaceForColumns(
space_builder.SetDiscardingMarginStrut();
}
space_builder.SetNeedsBaseline(parent_space.NeedsBaseline());
space_builder.SetBaselineAlgorithmType(parent_space.BaselineAlgorithmType());
return space_builder.ToConstraintSpace();
}
......
......@@ -1010,6 +1010,9 @@ virtual/layout_ng_block_frag/external/wpt/css/css-break/tall-line-in-short-fragm
virtual/layout_ng_block_frag/external/wpt/css/css-break/tall-line-in-short-fragmentainer-002.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-break/trailing-child-margin-000.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-break/trailing-child-margin-002.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-multicol/baseline-001.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-multicol/baseline-007.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-multicol/baseline-008.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-006.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-007.html [ Pass ]
virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-008.html [ Pass ]
......@@ -1116,7 +1119,6 @@ crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/hit-test-end-of-colu
crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/hit-test-end-of-column-with-line-height.html [ Crash Failure ]
crbug.com/1066629 virtual/layout_ng_block_frag/fast/multicol/hit-test-translate-z.html [ Failure ]
crbug.com/829181 virtual/layout_ng_block_frag/fast/multicol/infinitely-tall-content-in-outer-crash.html [ Skip ]
crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/inline-block-baseline.html [ Failure ]
crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/inline-getclientrects.html [ Failure ]
crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/insane-column-gap.html [ Failure ]
crbug.com/1066626 virtual/layout_ng_block_frag/fast/multicol/layers-split-across-columns.html [ Failure ]
......@@ -3328,6 +3330,9 @@ crbug.com/829028 external/wpt/css/css-break/trailing-child-margin-000.html [ Fai
crbug.com/829028 external/wpt/css/css-break/trailing-child-margin-002.html [ Failure ]
crbug.com/967329 external/wpt/css/css-multicol/columnfill-auto-max-height-001.html [ Failure ]
crbug.com/967329 external/wpt/css/css-multicol/columnfill-auto-max-height-002.html [ Failure ]
crbug.com/829028 external/wpt/css/css-multicol/baseline-001.html [ Failure ]
crbug.com/829028 external/wpt/css/css-multicol/baseline-007.html [ Failure ]
crbug.com/829028 external/wpt/css/css-multicol/baseline-008.html [ Failure ]
crbug.com/990240 external/wpt/css/css-multicol/multicol-breaking-000.html [ Failure ]
crbug.com/990240 external/wpt/css/css-multicol/multicol-breaking-001.html [ Failure ]
crbug.com/481431 external/wpt/css/css-multicol/multicol-breaking-004.html [ Failure ]
......
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
PASS
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<link rel="match" href="baseline-000-ref.html">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="display:flex; align-items:baseline;">
PA
<div style="columns:2; column-fill:auto; height:5em;">
SS
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>There should be a green square below.</p>
<div style="width:100px; height:100px; background:green;"></div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<meta name="assert" content="The multicol container here has no baseline, since we're only supposed to look for a baseline in the first column, which has no lines at all.">
<link rel="match" href="baseline-001-ref.html">
<p>There should be a green square below.</p>
<div style="display:flex; align-items:baseline;">
<div style="width:50px; height:100px; background:green;"></div>
<div style="columns:2; height:100px; column-fill:auto;">
<div style="width:50px; height:100px; background:green;"></div>
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="line-height:2em;">
<br>
PASS
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<link rel="match" href="baseline-002-ref.html">
<meta name="assert" content="Make sure that baseline propagation doesn't take place before column balancing is finished.">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="display:flex; align-items:baseline;">
PA
<div style="columns:3; orphans:1; widows:1; line-height:2em;">
<div style="break-inside:avoid; height:2em;"></div>
SS<br>
<br>
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
PASS
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<link rel="match" href="baseline-003-ref.html">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="display:flex; align-items:baseline;">
PA
<div style="columns:3;">
<div style="column-span:all;">SS</div>
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="padding-top:2em;">
PASS
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<link rel="match" href="baseline-004-ref.html">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="display:flex; align-items:baseline;">
PA
<div style="columns:3;">
<div style="column-span:all; height:2em;"></div>
<div style="column-span:all;">SS</div>
<br>
</div>
</div>
<!DOCTYPE html>
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
PASS
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<link rel="match" href="baseline-005-ref.html">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="display:flex; align-items:baseline;">
PA
<div style="columns:3;">
SS
<div style="column-span:all;"><br></div>
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="padding-top:33px;">PASS</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<link rel="match" href="baseline-006-ref.html">
<p>The word "PASS" should be seen below, with letters baseline aligned.</p>
<div style="display:flex; align-items:baseline;">
PA
<div style="columns:3;">
<div style="height:99px;"></div>
<div style="column-span:all;">SS</div>
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>There should be a green square below.</p>
<div style="width:100px; height:100px; background:green"></div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<meta name="assert" content="The first column has no baseline. The column after the spanner does have one, but we're not supposed to look beyond the first column (and any spanners).">
<link rel="match" href="baseline-007-ref.html">
<p>There should be a green square below.</p>
<div style="display:flex; align-items:baseline;">
<div style="width:50px; height:100px; background:green;"></div>
<div style="columns:3; width:50px; line-height:40px; background:green;">
<div style="height:90px;"></div>
<div style="column-span:all; height:30px;"></div>
<br>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<p>There should be a green square below.</p>
<div style="width:100px; height:100px; background:green;"></div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1">
<link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export">
<meta name="assert" content="According to the spec, a multicol container has no last baseline, only a first baseline. So, when aligning with an inline-block, the block-end outer edge of the multicol is what's used for alignment.">
<link rel="match" href="baseline-008-ref.html">
<style>
.part {
display: inline-block;
width: 50px;
height: 100px;
background: green;
}
.multicol {
columns: 2;
column-fill: auto;
}
</style>
<p>There should be a green square below.</p>
<div class="part"></div><div class="part multicol">
<br>
</div>
<!DOCTYPE html>
<style>
.letter { float:left; width:1em; text-align:center; }
</style>
<p>The word "PASS" should be seen below, on a straight line, with a somewhat large letter spacing.</p>
<div style="line-height:2em; font-family:monospace;">
<div class="letter">P</div>
<div class="letter">A</div>
<div class="letter">S</div>
<div class="letter">S</div>
</div>
<!DOCTYPE html>
<style>
.letter { text-align:center; width:1em; }
</style>
<p>The word "PASS" should be seen below, on a straight line, with a somewhat large letter spacing.</p>
<div style="line-height:2em; font-family:monospace;">
<div style="display:inline-block;" class="letter">P</div><div style="display:inline-block;">
<div style="columns:3; column-gap:0; width:3em;">
<div class="letter">A</div>
<div class="letter">S</div>
<div class="letter">S</div>
</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