blob: cb2e90637d8304842522e37722d97e4acedd59b7 [file] [log] [blame]
// Copyright 2016 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_out_of_flow_layout_part.h"
#include "core/layout/ng/ng_absolute_utils.h"
#include "core/layout/ng/ng_block_node.h"
#include "core/layout/ng/ng_box_fragment.h"
#include "core/layout/ng/ng_constraint_space_builder.h"
#include "core/layout/ng/ng_fragment.h"
#include "core/layout/ng/ng_length_utils.h"
#include "core/layout/ng/ng_physical_fragment.h"
#include "core/style/ComputedStyle.h"
namespace blink {
NGOutOfFlowLayoutPart::NGOutOfFlowLayoutPart(
PassRefPtr<const ComputedStyle> container_style,
NGLogicalSize container_size) {
NGWritingMode writing_mode(
FromPlatformWritingMode(container_style->getWritingMode()));
NGBoxStrut borders = ComputeBorders(*container_style);
parent_border_offset_ =
NGLogicalOffset{borders.inline_start, borders.block_start};
parent_border_physical_offset_ = parent_border_offset_.ConvertToPhysical(
writing_mode, container_style->direction(),
container_size.ConvertToPhysical(writing_mode), NGPhysicalSize());
NGLogicalSize space_size = container_size;
space_size.block_size -= borders.BlockSum();
space_size.inline_size -= borders.InlineSum();
// Initialize ConstraintSpace
NGConstraintSpaceBuilder space_builder(writing_mode);
space_builder.SetAvailableSize(space_size);
space_builder.SetPercentageResolutionSize(space_size);
space_builder.SetIsNewFormattingContext(true);
space_builder.SetTextDirection(container_style->direction());
parent_space_ = space_builder.ToConstraintSpace();
}
void NGOutOfFlowLayoutPart::Layout(NGBlockNode& node,
NGStaticPosition static_position,
NGFragment** fragment_out,
NGLogicalOffset* offset) {
// Adjust the static_position origin. The static_position coordinate origin is
// relative to the parent's border box, ng_absolute_utils expects it to be
// relative to the parent's padding box.
static_position.offset -= parent_border_physical_offset_;
NGFragment* fragment = nullptr;
Optional<MinAndMaxContentSizes> inline_estimate;
Optional<LayoutUnit> block_estimate;
if (AbsoluteNeedsChildInlineSize(*node.Style())) {
inline_estimate = node.ComputeMinAndMaxContentSizesSync();
}
NGAbsolutePhysicalPosition node_position =
ComputePartialAbsoluteWithChildInlineSize(
*parent_space_, *node.Style(), static_position, inline_estimate);
if (AbsoluteNeedsChildBlockSize(*node.Style())) {
fragment = GenerateFragment(node, block_estimate, node_position);
block_estimate = fragment->BlockSize();
}
ComputeFullAbsoluteWithChildBlockSize(*parent_space_, *node.Style(),
static_position, block_estimate,
&node_position);
// Skip this step if we produced a fragment when estimating the block size.
if (!fragment) {
block_estimate =
node_position.size.ConvertToLogical(parent_space_->WritingMode())
.block_size;
fragment = GenerateFragment(node, block_estimate, node_position);
}
*fragment_out = fragment;
// Compute logical offset, NGAbsolutePhysicalPosition is calculated relative
// to the padding box so add back the parent's borders.
NGBoxStrut inset = node_position.inset.ConvertToLogical(
parent_space_->WritingMode(), parent_space_->Direction());
offset->inline_offset =
inset.inline_start + parent_border_offset_.inline_offset;
offset->block_offset = inset.block_start + parent_border_offset_.block_offset;
}
NGFragment* NGOutOfFlowLayoutPart::GenerateFragment(
NGBlockNode& node,
const Optional<LayoutUnit>& block_estimate,
const NGAbsolutePhysicalPosition node_position) {
// The fragment is generated in one of these two scenarios:
// 1. To estimate child's block size, in this case block_size is parent's
// available size.
// 2. To compute final fragment, when block size is known from the absolute
// position calculation.
LayoutUnit inline_size =
node_position.size.ConvertToLogical(parent_space_->WritingMode())
.inline_size;
LayoutUnit block_size = block_estimate
? *block_estimate
: parent_space_->AvailableSize().block_size;
NGLogicalSize available_size{inline_size, block_size};
NGConstraintSpaceBuilder builder(parent_space_->WritingMode());
builder.SetAvailableSize(available_size);
builder.SetPercentageResolutionSize(parent_space_->AvailableSize());
if (block_estimate)
builder.SetIsFixedSizeBlock(true);
builder.SetIsFixedSizeInline(true);
builder.SetIsNewFormattingContext(true);
NGConstraintSpace* space = builder.ToConstraintSpace();
NGPhysicalFragment* fragment = node.Layout(space);
// TODO(ikilpatrick): the writing mode switching here looks wrong.
return new NGBoxFragment(parent_space_->WritingMode(),
parent_space_->Direction(),
toNGPhysicalBoxFragment(fragment));
}
DEFINE_TRACE(NGOutOfFlowLayoutPart) {
visitor->trace(parent_space_);
}
} // namespace blink