blob: 47eee440215426033ab4f276b4f0c6ec75da472f [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/layout/ng/ng_column_layout_algorithm.h"
#include "core/layout/ng/inline/ng_baseline.h"
#include "core/layout/ng/ng_block_layout_algorithm.h"
#include "core/layout/ng/ng_box_fragment.h"
#include "core/layout/ng/ng_constraint_space_builder.h"
#include "core/layout/ng/ng_length_utils.h"
#include "core/layout/ng/ng_out_of_flow_layout_part.h"
#include "core/layout/ng/ng_physical_box_fragment.h"
namespace blink {
NGColumnLayoutAlgorithm::NGColumnLayoutAlgorithm(NGBlockNode node,
const NGConstraintSpace& space,
NGBreakToken* break_token)
: NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {}
RefPtr<NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
Optional<MinMaxSize> min_max_size;
if (NeedMinMaxSize(ConstraintSpace(), Style()))
min_max_size = ComputeMinMaxSize();
NGBoxStrut border_scrollbar_padding = CalculateBorderScrollbarPadding(
ConstraintSpace(), Style(), Node().GetLayoutObject());
NGLogicalSize border_box_size =
CalculateBorderBoxSize(ConstraintSpace(), Style(), min_max_size);
content_box_size_ =
CalculateContentBoxSize(border_box_size, border_scrollbar_padding);
RefPtr<NGConstraintSpace> child_space = CreateConstraintSpaceForColumns();
if (border_box_size.block_size == NGSizeIndefinite) {
// Get the block size from the columns if it's auto.
border_box_size.block_size = child_space->AvailableSize().block_size +
border_scrollbar_padding.BlockSum();
}
container_builder_.SetSize(border_box_size);
NGWritingMode writing_mode = ConstraintSpace().WritingMode();
RefPtr<NGBlockBreakToken> break_token = BreakToken();
NGLogicalSize overflow;
LayoutUnit column_inline_offset;
LayoutUnit column_inline_progression =
child_space->AvailableSize().inline_size + ResolveUsedColumnGap(Style());
do {
// Lay out one column. Each column will become a fragment.
NGBlockLayoutAlgorithm child_algorithm(Node(), *child_space.Get(),
break_token.Get());
RefPtr<NGLayoutResult> result = child_algorithm.Layout();
RefPtr<NGPhysicalBoxFragment> column(
ToNGPhysicalBoxFragment(result->PhysicalFragment().Get()));
NGLogicalOffset logical_offset(column_inline_offset, LayoutUnit());
container_builder_.AddChild(column, logical_offset);
NGLogicalSize size = NGBoxFragment(writing_mode, *column).Size();
NGLogicalOffset end_offset =
logical_offset + NGLogicalOffset(size.inline_size, size.block_size);
overflow.inline_size =
std::max(overflow.inline_size, end_offset.inline_offset);
overflow.block_size =
std::max(overflow.block_size, end_offset.block_offset);
column_inline_offset += column_inline_progression;
break_token = ToNGBlockBreakToken(column->BreakToken());
} while (break_token && !break_token->IsFinished());
container_builder_.SetOverflowSize(overflow);
NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run();
// TODO(mstensho): Propagate baselines.
return container_builder_.ToBoxFragment();
}
Optional<MinMaxSize> NGColumnLayoutAlgorithm::ComputeMinMaxSize() const {
DCHECK(0) << "Min/max calculation not yet implemented for multicol";
return WTF::nullopt;
}
RefPtr<NGConstraintSpace>
NGColumnLayoutAlgorithm::CreateConstraintSpaceForColumns() const {
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
NGLogicalSize adjusted_size = content_box_size_;
adjusted_size.inline_size =
ResolveUsedColumnInlineSize(adjusted_size.inline_size, Style());
// TODO(mstensho): Implement column balancing. For now just set it to some
// arbitrary positive length if height is auto, so that we don't get stuck in
// infinite loops, because of no block progression (negative, even) between
// one fragmentainer and the next.
if (adjusted_size.block_size == NGSizeIndefinite)
adjusted_size.block_size = LayoutUnit(42);
// To ensure progression, we need something larger than 0 here. The spec
// actually says that fragmentainers have to accept at least 1px of content.
adjusted_size.block_size = std::max(adjusted_size.block_size, LayoutUnit(1));
space_builder.SetAvailableSize(adjusted_size);
space_builder.SetPercentageResolutionSize(adjusted_size);
if (NGBaseline::ShouldPropagateBaselines(Node()))
space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
space_builder.SetFragmentationType(kFragmentColumn);
space_builder.SetFragmentainerSpaceAvailable(adjusted_size.block_size);
space_builder.SetIsNewFormattingContext(true);
space_builder.SetIsAnonymous(true);
return space_builder.ToConstraintSpace(
FromPlatformWritingMode(Style().GetWritingMode()));
}
} // namespace Blink