blob: 476ad7fb1f904cbd3ff5378f166529224212bafc [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_page_layout_algorithm.h"
#include <algorithm>
#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 {
NGPageLayoutAlgorithm::NGPageLayoutAlgorithm(NGBlockNode node,
const NGConstraintSpace& space,
NGBreakToken* break_token)
: NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {}
scoped_refptr<NGLayoutResult> NGPageLayoutAlgorithm::Layout() {
Optional<MinMaxSize> min_max_size;
if (NeedMinMaxSize(ConstraintSpace(), Style()))
min_max_size = ComputeMinMaxSize();
NGBoxStrut border_scrollbar_padding =
CalculateBorderScrollbarPadding(ConstraintSpace(), Style(), Node());
NGLogicalSize border_box_size =
CalculateBorderBoxSize(ConstraintSpace(), Style(), min_max_size);
NGLogicalSize content_box_size =
CalculateContentBoxSize(border_box_size, border_scrollbar_padding);
NGLogicalSize page_size = content_box_size;
scoped_refptr<NGConstraintSpace> child_space =
CreateConstraintSpaceForPages(page_size);
container_builder_.SetInlineSize(border_box_size.inline_size);
WritingMode writing_mode = ConstraintSpace().GetWritingMode();
scoped_refptr<NGBlockBreakToken> break_token = BreakToken();
LayoutUnit intrinsic_block_size;
NGLogicalOffset page_offset(border_scrollbar_padding.StartOffset());
NGLogicalOffset page_progression;
if (Style().OverflowY() == EOverflow::kWebkitPagedX) {
page_progression.inline_offset = page_size.inline_size;
} else {
// TODO(mstensho): Handle auto block size.
page_progression.block_offset = page_size.block_size;
}
do {
// Lay out one page. Each page will become a fragment.
NGBlockLayoutAlgorithm child_algorithm(Node(), *child_space.get(),
break_token.get());
scoped_refptr<NGLayoutResult> result = child_algorithm.Layout();
scoped_refptr<NGPhysicalBoxFragment> page(
ToNGPhysicalBoxFragment(result->PhysicalFragment().get()));
container_builder_.AddChild(result, page_offset);
NGBoxFragment logical_fragment(writing_mode, *page);
intrinsic_block_size =
std::max(intrinsic_block_size,
page_offset.block_offset + logical_fragment.BlockSize());
page_offset += page_progression;
break_token = ToNGBlockBreakToken(page->BreakToken());
} while (break_token && !break_token->IsFinished());
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
// Recompute the block-axis size now that we know our content size.
border_box_size.block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), intrinsic_block_size);
container_builder_.SetBlockSize(border_box_size.block_size);
NGOutOfFlowLayoutPart(&container_builder_, Node().IsAbsoluteContainer(),
Node().IsFixedContainer(), Node().GetScrollbarSizes(),
ConstraintSpace(), Style())
.Run();
// TODO(mstensho): Propagate baselines.
return container_builder_.ToBoxFragment();
}
Optional<MinMaxSize> NGPageLayoutAlgorithm::ComputeMinMaxSize() const {
return NGBlockLayoutAlgorithm(Node(), ConstraintSpace()).ComputeMinMaxSize();
}
scoped_refptr<NGConstraintSpace>
NGPageLayoutAlgorithm::CreateConstraintSpaceForPages(
const NGLogicalSize& page_size) const {
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
space_builder.SetAvailableSize(page_size);
space_builder.SetPercentageResolutionSize(page_size);
if (NGBaseline::ShouldPropagateBaselines(Node()))
space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
// TODO(mstensho): Handle auto block size. For now just disable fragmentation
// if block size is auto. With the current approach, we'll just end up with
// one tall page. This is only correct if there are no explicit page breaks.
if (page_size.block_size != NGSizeIndefinite) {
space_builder.SetFragmentationType(kFragmentPage);
space_builder.SetFragmentainerBlockSize(page_size.block_size);
space_builder.SetFragmentainerSpaceAtBfcStart(page_size.block_size);
}
space_builder.SetIsNewFormattingContext(true);
space_builder.SetIsAnonymous(true);
return space_builder.ToConstraintSpace(Style().GetWritingMode());
}
} // namespace blink