Commit 620f2fc2 authored by mstensho's avatar mstensho Committed by Commit bot

[LayoutNG] Correct inline size for children of multicol containers.

This will lay out multicol containers in one single tall column, without any
support for fragmentation or column balancing.

Also had to disable creation of the anonymous LayoutMultiColumnFlowThread child
of multicol containers, since that's not going to be used in LayoutNG.

The algorithm for calculating the used values of column-width and column-count
can be found here: https://drafts.csswg.org/css-multicol-1/#pseudo-algorithm

Review-Url: https://codereview.chromium.org/2528203002
Cr-Commit-Position: refs/heads/master@{#434971}
parent 38f0f99f
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "core/layout/shapes/ShapeOutsideInfo.h" #include "core/layout/shapes/ShapeOutsideInfo.h"
#include "core/paint/BlockFlowPaintInvalidator.h" #include "core/paint/BlockFlowPaintInvalidator.h"
#include "core/paint/PaintLayer.h" #include "core/paint/PaintLayer.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "wtf/PtrUtil.h" #include "wtf/PtrUtil.h"
#include <memory> #include <memory>
...@@ -4178,6 +4179,9 @@ LayoutMultiColumnFlowThread* LayoutBlockFlow::createMultiColumnFlowThread( ...@@ -4178,6 +4179,9 @@ LayoutMultiColumnFlowThread* LayoutBlockFlow::createMultiColumnFlowThread(
void LayoutBlockFlow::createOrDestroyMultiColumnFlowThreadIfNeeded( void LayoutBlockFlow::createOrDestroyMultiColumnFlowThreadIfNeeded(
const ComputedStyle* oldStyle) { const ComputedStyle* oldStyle) {
if (RuntimeEnabledFeatures::layoutNGEnabled())
return;
// Paged overflow trumps multicol in this implementation. Ideally, it should // Paged overflow trumps multicol in this implementation. Ideally, it should
// be possible to have both paged overflow and multicol on the same element, // be possible to have both paged overflow and multicol on the same element,
// but then we need two flow threads. Anyway, this is nothing to worry about // but then we need two flow threads. Anyway, this is nothing to worry about
......
...@@ -220,6 +220,11 @@ NGLayoutStatus NGBlockLayoutAlgorithm::Layout( ...@@ -220,6 +220,11 @@ NGLayoutStatus NGBlockLayoutAlgorithm::Layout(
space_builder_ = space_builder_ =
new NGConstraintSpaceBuilder(constraint_space_->WritingMode()); new NGConstraintSpaceBuilder(constraint_space_->WritingMode());
if (Style().specifiesColumns()) {
space_builder_->SetFragmentationType(FragmentColumn);
adjusted_inline_size =
ResolveUsedColumnInlineSize(adjusted_inline_size, Style());
}
space_builder_->SetAvailableSize( space_builder_->SetAvailableSize(
NGLogicalSize(adjusted_inline_size, adjusted_block_size)); NGLogicalSize(adjusted_inline_size, adjusted_block_size));
space_builder_->SetPercentageResolutionSize( space_builder_->SetPercentageResolutionSize(
......
...@@ -228,6 +228,53 @@ LayoutUnit ComputeBlockSizeForFragment(const NGConstraintSpace& constraintSpace, ...@@ -228,6 +228,53 @@ LayoutUnit ComputeBlockSizeForFragment(const NGConstraintSpace& constraintSpace,
return extent; return extent;
} }
int ResolveUsedColumnCount(int computed_count,
LayoutUnit computed_size,
LayoutUnit used_gap,
LayoutUnit available_size) {
if (computed_size == NGSizeIndefinite) {
DCHECK(computed_count);
return computed_count;
}
DCHECK(computed_size > LayoutUnit());
int count_from_width =
((available_size + used_gap) / (computed_size + used_gap)).toInt();
count_from_width = std::max(1, count_from_width);
if (!computed_count)
return count_from_width;
return std::max(1, std::min(computed_count, count_from_width));
}
LayoutUnit ResolveUsedColumnInlineSize(int computed_count,
LayoutUnit computed_size,
LayoutUnit used_gap,
LayoutUnit available_size) {
int used_count = ResolveUsedColumnCount(computed_count, computed_size,
used_gap, available_size);
return ((available_size + used_gap) / used_count) - used_gap;
}
LayoutUnit ResolveUsedColumnInlineSize(LayoutUnit available_size,
const ComputedStyle& style) {
// Should only attempt to resolve this if columns != auto.
DCHECK(!style.hasAutoColumnCount() || !style.hasAutoColumnWidth());
LayoutUnit computed_size =
style.hasAutoColumnWidth()
? NGSizeIndefinite
: std::max(LayoutUnit(1), LayoutUnit(style.columnWidth()));
int computed_count = style.hasAutoColumnCount() ? 0 : style.columnCount();
LayoutUnit used_gap = ResolveUsedColumnGap(style);
return ResolveUsedColumnInlineSize(computed_count, computed_size, used_gap,
available_size);
}
LayoutUnit ResolveUsedColumnGap(const ComputedStyle& style) {
if (style.hasNormalColumnGap())
return LayoutUnit(style.getFontDescription().computedPixelSize());
return LayoutUnit(style.columnGap());
}
NGBoxStrut ComputeMargins(const NGConstraintSpace& constraintSpace, NGBoxStrut ComputeMargins(const NGConstraintSpace& constraintSpace,
const ComputedStyle& style, const ComputedStyle& style,
const NGWritingMode writing_mode, const NGWritingMode writing_mode,
......
...@@ -67,6 +67,24 @@ CORE_EXPORT LayoutUnit ComputeBlockSizeForFragment(const NGConstraintSpace&, ...@@ -67,6 +67,24 @@ CORE_EXPORT LayoutUnit ComputeBlockSizeForFragment(const NGConstraintSpace&,
const ComputedStyle&, const ComputedStyle&,
LayoutUnit contentSize); LayoutUnit contentSize);
// Based on available inline size, CSS computed column-width, CSS computed
// column-count and CSS used column-gap, return CSS used column-count.
CORE_EXPORT int ResolveUsedColumnCount(int computed_count,
LayoutUnit computed_size,
LayoutUnit used_gap,
LayoutUnit available_size);
// Based on available inline size, CSS computed column-width, CSS computed
// column-count and CSS used column-gap, return CSS used column-width.
CORE_EXPORT LayoutUnit ResolveUsedColumnInlineSize(int computed_count,
LayoutUnit computed_size,
LayoutUnit used_gap,
LayoutUnit available_size);
CORE_EXPORT LayoutUnit ResolveUsedColumnInlineSize(LayoutUnit available_size,
const ComputedStyle&);
CORE_EXPORT LayoutUnit ResolveUsedColumnGap(const ComputedStyle&);
CORE_EXPORT NGBoxStrut ComputeMargins(const NGConstraintSpace&, CORE_EXPORT NGBoxStrut ComputeMargins(const NGConstraintSpace&,
const ComputedStyle&, const ComputedStyle&,
const NGWritingMode writing_mode, const NGWritingMode writing_mode,
......
...@@ -365,5 +365,70 @@ TEST_F(NGLengthUtilsTest, testAutoMargins) { ...@@ -365,5 +365,70 @@ TEST_F(NGLengthUtilsTest, testAutoMargins) {
EXPECT_EQ(LayoutUnit(5000), margins.inline_end); EXPECT_EQ(LayoutUnit(5000), margins.inline_end);
} }
// Simple wrappers that don't use LayoutUnit(). Their only purpose is to make
// the tests below humanly readable (to make the expectation expressions fit on
// one line each). Passing 0 for column width or column count means "auto".
int GetUsedColumnWidth(int computed_column_count,
int computed_column_width,
int used_column_gap,
int available_inline_size) {
LayoutUnit column_width(computed_column_width);
if (!computed_column_width)
column_width = LayoutUnit(NGSizeIndefinite);
return ResolveUsedColumnInlineSize(computed_column_count, column_width,
LayoutUnit(used_column_gap),
LayoutUnit(available_inline_size))
.toInt();
}
int GetUsedColumnCount(int computed_column_count,
int computed_column_width,
int used_column_gap,
int available_inline_size) {
LayoutUnit column_width(computed_column_width);
if (!computed_column_width)
column_width = LayoutUnit(NGSizeIndefinite);
return ResolveUsedColumnCount(computed_column_count, column_width,
LayoutUnit(used_column_gap),
LayoutUnit(available_inline_size));
}
TEST_F(NGLengthUtilsTest, testColumnWidthAndCount) {
EXPECT_EQ(100, GetUsedColumnWidth(0, 100, 0, 300));
EXPECT_EQ(3, GetUsedColumnCount(0, 100, 0, 300));
EXPECT_EQ(150, GetUsedColumnWidth(0, 101, 0, 300));
EXPECT_EQ(2, GetUsedColumnCount(0, 101, 0, 300));
EXPECT_EQ(300, GetUsedColumnWidth(0, 151, 0, 300));
EXPECT_EQ(1, GetUsedColumnCount(0, 151, 0, 300));
EXPECT_EQ(300, GetUsedColumnWidth(0, 1000, 0, 300));
EXPECT_EQ(1, GetUsedColumnCount(0, 1000, 0, 300));
EXPECT_EQ(100, GetUsedColumnWidth(0, 100, 10, 320));
EXPECT_EQ(3, GetUsedColumnCount(0, 100, 10, 320));
EXPECT_EQ(150, GetUsedColumnWidth(0, 101, 10, 310));
EXPECT_EQ(2, GetUsedColumnCount(0, 101, 10, 310));
EXPECT_EQ(300, GetUsedColumnWidth(0, 151, 10, 300));
EXPECT_EQ(1, GetUsedColumnCount(0, 151, 10, 300));
EXPECT_EQ(300, GetUsedColumnWidth(0, 1000, 10, 300));
EXPECT_EQ(1, GetUsedColumnCount(0, 1000, 10, 300));
EXPECT_EQ(125, GetUsedColumnWidth(4, 0, 0, 500));
EXPECT_EQ(4, GetUsedColumnCount(4, 0, 0, 500));
EXPECT_EQ(125, GetUsedColumnWidth(4, 100, 0, 500));
EXPECT_EQ(4, GetUsedColumnCount(4, 100, 0, 500));
EXPECT_EQ(100, GetUsedColumnWidth(6, 100, 0, 500));
EXPECT_EQ(5, GetUsedColumnCount(6, 100, 0, 500));
EXPECT_EQ(100, GetUsedColumnWidth(0, 100, 0, 500));
EXPECT_EQ(5, GetUsedColumnCount(0, 100, 0, 500));
EXPECT_EQ(125, GetUsedColumnWidth(4, 0, 10, 530));
EXPECT_EQ(4, GetUsedColumnCount(4, 0, 10, 530));
EXPECT_EQ(125, GetUsedColumnWidth(4, 100, 10, 530));
EXPECT_EQ(4, GetUsedColumnCount(4, 100, 10, 530));
EXPECT_EQ(100, GetUsedColumnWidth(6, 100, 10, 540));
EXPECT_EQ(5, GetUsedColumnCount(6, 100, 10, 540));
EXPECT_EQ(100, GetUsedColumnWidth(0, 100, 10, 540));
EXPECT_EQ(5, GetUsedColumnCount(0, 100, 10, 540));
}
} // 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