blob: ec6e9df6a73508b95a2268d019f5797769ceaf2a [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_container_fragment_builder.h"
#include "core/layout/ng/ng_exclusion_space.h"
#include "core/layout/ng/ng_layout_result.h"
#include "core/layout/ng/ng_physical_fragment.h"
#include "core/layout/ng/ng_unpositioned_float.h"
#include "core/style/ComputedStyle.h"
namespace blink {
NGContainerFragmentBuilder::NGContainerFragmentBuilder(
scoped_refptr<const ComputedStyle> style,
NGWritingMode writing_mode,
TextDirection direction)
: NGBaseFragmentBuilder(std::move(style), writing_mode, direction) {}
NGContainerFragmentBuilder::~NGContainerFragmentBuilder() {}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::SetInlineSize(
LayoutUnit inline_size) {
DCHECK_GE(inline_size, LayoutUnit());
inline_size_ = inline_size;
return *this;
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::SetBfcOffset(
const NGBfcOffset& bfc_offset) {
bfc_offset_ = bfc_offset;
return *this;
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::SetEndMarginStrut(
const NGMarginStrut& end_margin_strut) {
end_margin_strut_ = end_margin_strut;
return *this;
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::SetExclusionSpace(
std::unique_ptr<const NGExclusionSpace> exclusion_space) {
exclusion_space_ = std::move(exclusion_space);
return *this;
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::SwapUnpositionedFloats(
Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats) {
unpositioned_floats_.swap(*unpositioned_floats);
return *this;
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild(
scoped_refptr<NGLayoutResult> child,
const NGLogicalOffset& child_offset) {
// Collect the child's out of flow descendants.
// child_offset is offset of inline_start/block_start vertex.
// Candidates need offset of top/left vertex.
const auto& ouf_of_flow_descendants = child->OutOfFlowPositionedDescendants();
if (!ouf_of_flow_descendants.IsEmpty()) {
NGLogicalOffset top_left_offset;
NGPhysicalSize child_size = child->PhysicalFragment()->Size();
switch (WritingMode()) {
case kHorizontalTopBottom:
top_left_offset =
(IsRtl(Direction()))
? NGLogicalOffset{child_offset.inline_offset + child_size.width,
child_offset.block_offset}
: child_offset;
break;
case kVerticalRightLeft:
case kSidewaysRightLeft:
top_left_offset =
(IsRtl(Direction()))
? NGLogicalOffset{child_offset.inline_offset +
child_size.height,
child_offset.block_offset + child_size.width}
: NGLogicalOffset{child_offset.inline_offset,
child_offset.block_offset + child_size.width};
break;
case kVerticalLeftRight:
case kSidewaysLeftRight:
top_left_offset = (IsRtl(Direction()))
? NGLogicalOffset{child_offset.inline_offset +
child_size.height,
child_offset.block_offset}
: child_offset;
break;
}
for (const NGOutOfFlowPositionedDescendant& descendant :
ouf_of_flow_descendants) {
oof_positioned_candidates_.push_back(
NGOutOfFlowPositionedCandidate{descendant, top_left_offset});
}
}
return AddChild(child->PhysicalFragment(), child_offset);
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild(
scoped_refptr<NGPhysicalFragment> child,
const NGLogicalOffset& child_offset) {
children_.push_back(std::move(child));
offsets_.push_back(child_offset);
return *this;
}
NGContainerFragmentBuilder&
NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
NGBlockNode child,
const NGLogicalOffset& child_offset) {
DCHECK(child);
oof_positioned_candidates_.push_back(NGOutOfFlowPositionedCandidate(
NGOutOfFlowPositionedDescendant{
child, NGStaticPosition::Create(WritingMode(), Direction(),
NGPhysicalOffset())},
child_offset));
child.SaveStaticOffsetForLegacy(child_offset);
return *this;
}
NGContainerFragmentBuilder&
NGContainerFragmentBuilder::AddInlineOutOfFlowChildCandidate(
NGBlockNode child,
const NGLogicalOffset& child_offset,
TextDirection line_direction) {
DCHECK(child);
oof_positioned_candidates_.push_back(NGOutOfFlowPositionedCandidate(
NGOutOfFlowPositionedDescendant{
child, NGStaticPosition::Create(WritingMode(), line_direction,
NGPhysicalOffset())},
child_offset, line_direction));
child.SaveStaticOffsetForLegacy(child_offset);
return *this;
}
NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddOutOfFlowDescendant(
NGOutOfFlowPositionedDescendant descendant) {
oof_positioned_descendants_.push_back(descendant);
return *this;
}
void NGContainerFragmentBuilder::GetAndClearOutOfFlowDescendantCandidates(
Vector<NGOutOfFlowPositionedDescendant>* descendant_candidates) {
DCHECK(descendant_candidates->IsEmpty());
descendant_candidates->ReserveCapacity(oof_positioned_candidates_.size());
DCHECK_GE(inline_size_, LayoutUnit());
DCHECK_GE(block_size_, LayoutUnit());
NGPhysicalSize builder_physical_size{Size().ConvertToPhysical(WritingMode())};
for (NGOutOfFlowPositionedCandidate& candidate : oof_positioned_candidates_) {
TextDirection direction =
candidate.is_line_relative ? candidate.line_direction : Direction();
NGPhysicalOffset child_offset = candidate.child_offset.ConvertToPhysical(
WritingMode(), direction, builder_physical_size, NGPhysicalSize());
NGStaticPosition builder_relative_position;
builder_relative_position.type = candidate.descendant.static_position.type;
builder_relative_position.offset =
child_offset + candidate.descendant.static_position.offset;
descendant_candidates->push_back(NGOutOfFlowPositionedDescendant{
candidate.descendant.node, builder_relative_position});
}
// Clear our current canidate list. This may get modified again if the
// current fragment is a containing block, and AddChild is called with a
// descendant from this list.
//
// The descendant may be a "position: absolute" which contains a "position:
// fixed" for example. (This fragment isn't the containing block for the
// fixed descendant).
oof_positioned_candidates_.clear();
}
} // namespace blink