diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc | 204 |
1 files changed, 113 insertions, 91 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc index 39f44dbe3bb..e62ccbc378e 100644 --- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc +++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc @@ -7,48 +7,61 @@ #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" -#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/text/writing_mode.h" namespace blink { +namespace { +// This routine returns true if inline_container should replace descendant's +// inline container. +bool IsInlineContainerForDescendant( + const NGOutOfFlowPositionedDescendant& descendant, + const LayoutObject* inline_container) { + return !descendant.inline_container && inline_container && + inline_container->IsLayoutInline() && + inline_container->CanContainOutOfFlowPositionedElement( + descendant.node.Style().GetPosition()); +} +} // namespace + NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild( - const NGLayoutResult& child, - const NGLogicalOffset& child_offset) { + const NGPhysicalContainerFragment& child, + const LogicalOffset& child_offset, + const LayoutInline* inline_container) { // 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& out_of_flow_descendants = child.OutOfFlowPositionedDescendants(); - if (!out_of_flow_descendants.IsEmpty()) { - NGLogicalOffset top_left_offset; - NGPhysicalSize child_size = child.PhysicalFragment()->Size(); + if (child.HasOutOfFlowPositionedDescendants()) { + const auto& out_of_flow_descendants = + child.OutOfFlowPositionedDescendants(); + LogicalOffset top_left_offset; + PhysicalSize child_size = child.Size(); switch (GetWritingMode()) { case WritingMode::kHorizontalTb: top_left_offset = (IsRtl(Direction())) - ? NGLogicalOffset{child_offset.inline_offset + child_size.width, - child_offset.block_offset} + ? LogicalOffset{child_offset.inline_offset + child_size.width, + child_offset.block_offset} : child_offset; break; case WritingMode::kVerticalRl: case WritingMode::kSidewaysRl: 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}; + ? LogicalOffset{child_offset.inline_offset + child_size.height, + child_offset.block_offset + child_size.width} + : LogicalOffset{child_offset.inline_offset, + child_offset.block_offset + child_size.width}; break; case WritingMode::kVerticalLr: case WritingMode::kSidewaysLr: - top_left_offset = (IsRtl(Direction())) - ? NGLogicalOffset{child_offset.inline_offset + - child_size.height, - child_offset.block_offset} - : child_offset; + top_left_offset = + (IsRtl(Direction())) + ? LogicalOffset{child_offset.inline_offset + child_size.height, + child_offset.block_offset} + : child_offset; break; } @@ -62,44 +75,62 @@ NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild( // </div> // TODO(layout-dev): This code should eventually be removed once we handle // relative positioned objects directly in the fragment tree. - if (LayoutBox* child_box = - ToLayoutBoxOrNull(child.PhysicalFragment()->GetLayoutObject())) { - top_left_offset += - NGPhysicalOffset(child_box->OffsetForInFlowPosition()) - .ConvertToLogical(GetWritingMode(), Direction(), NGPhysicalSize(), - NGPhysicalSize()); + if (const LayoutBox* child_box = + ToLayoutBoxOrNull(child.GetLayoutObject())) { + top_left_offset += PhysicalOffset(child_box->OffsetForInFlowPosition()) + .ConvertToLogical(GetWritingMode(), Direction(), + PhysicalSize(), PhysicalSize()); } - for (const NGOutOfFlowPositionedDescendant& descendant : + for (NGOutOfFlowPositionedDescendant& descendant : out_of_flow_descendants) { + if (IsInlineContainerForDescendant(descendant, inline_container)) { + descendant.inline_container = inline_container; + } oof_positioned_candidates_.push_back( NGOutOfFlowPositionedCandidate(descendant, top_left_offset)); } } - if (child.HasOrthogonalFlowRoots()) + // For the |has_orthogonal_flow_roots_| flag, we don't care about the type of + // child (OOF-positioned, etc), it is for *any* descendant. + if (child.HasOrthogonalFlowRoots() || + !IsParallelWritingMode(child.Style().GetWritingMode(), + Style().GetWritingMode())) has_orthogonal_flow_roots_ = true; // We only need to report if inflow or floating elements depend on the // percentage resolution block-size. OOF-positioned children resolve their // percentages against the "final" size of their parent. - if (child.DependsOnPercentageBlockSize() && - !child.PhysicalFragment()->IsOutOfFlowPositioned()) - has_child_that_depends_on_percentage_block_size_ = true; - - if (child.MayHaveDescendantAboveBlockStart() && - !child.PhysicalFragment()->IsBlockFormattingContextRoot()) + if (child.DependsOnPercentageBlockSize() && !child.IsOutOfFlowPositioned()) + has_descendant_that_depends_on_percentage_block_size_ = true; + + // The |may_have_descendant_above_block_start_| flag is used to determine if + // a fragment can be re-used when floats are present. We only are about: + // - Inflow children who are positioned above our block-start edge. + // - Any inflow descendants (within the same formatting-context) that *may* + // be positioned above our block-start edge. + if ((child_offset.block_offset < LayoutUnit() && + !child.IsOutOfFlowPositioned()) || + (!child.IsBlockFormattingContextRoot() && + child.MayHaveDescendantAboveBlockStart())) may_have_descendant_above_block_start_ = true; - return AddChild(child.PhysicalFragment(), child_offset); -} + // Compute |has_floating_descendants_| to optimize tree traversal in paint. + if (!has_floating_descendants_) { + if (child.IsFloating()) { + has_floating_descendants_ = true; + } else { + if (!child.IsBlockFormattingContextRoot() && + child.HasFloatingDescendants()) + has_floating_descendants_ = true; + } + } -NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild( - scoped_refptr<const NGPhysicalFragment> child, - const NGLogicalOffset& child_offset) { - NGBreakToken* child_break_token = child->BreakToken(); + // Collect any (block) break tokens. + NGBreakToken* child_break_token = child.BreakToken(); if (child_break_token && has_block_fragmentation_) { - switch (child->Type()) { + switch (child.Type()) { case NGPhysicalFragment::kFragmentBox: case NGPhysicalFragment::kFragmentRenderedLegend: if (To<NGBlockBreakToken>(child_break_token)->HasLastResortBreak()) @@ -119,61 +150,54 @@ NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild( } } - // Compute |has_floating_descendants_| to optimize tree traversal in paint. - if (!has_floating_descendants_) { - if (child->IsFloating()) { - has_floating_descendants_ = true; - } else { - auto* child_container = DynamicTo<NGPhysicalContainerFragment>(*child); - if (child_container && !child->IsBlockFormattingContextRoot() && - child_container->HasFloatingDescendants()) - has_floating_descendants_ = true; - } - } - - if (child_offset.block_offset < LayoutUnit()) - may_have_descendant_above_block_start_ = true; + AddChildInternal(&child, child_offset); + return *this; +} - if (!IsParallelWritingMode(child->Style().GetWritingMode(), - Style().GetWritingMode())) - has_orthogonal_flow_roots_ = true; +void NGContainerFragmentBuilder::AddChildInternal( + scoped_refptr<const NGPhysicalFragment> child, + const LogicalOffset& child_offset) { + // In order to know where list-markers are within the children list (for the + // |NGSimplifiedLayoutAlgorithm|) we always place them as the first child. + if (child->IsListMarker()) { + children_.push_front(ChildWithOffset(child_offset, std::move(child))); + return; + } - children_.emplace_back(std::move(child)); - offsets_.push_back(child_offset); - return *this; + children_.emplace_back(child_offset, std::move(child)); } -NGLogicalOffset NGContainerFragmentBuilder::GetChildOffset( - const LayoutObject* child) const { - for (wtf_size_t i = 0; i < children_.size(); ++i) { - if (children_[i]->GetLayoutObject() == child) - return offsets_[i]; +LogicalOffset NGContainerFragmentBuilder::GetChildOffset( + const LayoutObject* object) const { + for (const auto& child : children_) { + if (child.fragment->GetLayoutObject() == object) + return child.offset; // TODO(layout-dev): ikilpatrick thinks we may need to traverse // further than the initial line-box children for a nested inline // container. We could not come up with a testcase, it would be // something with split inlines, and nested oof/fixed descendants maybe. - if (children_[i]->IsLineBox()) { + if (child.fragment->IsLineBox()) { const auto& line_box_fragment = - To<NGPhysicalLineBoxFragment>(*children_[i]); + To<NGPhysicalLineBoxFragment>(*child.fragment); for (const auto& line_box_child : line_box_fragment.Children()) { - if (line_box_child->GetLayoutObject() == child) { - return offsets_[i] + line_box_child.Offset().ConvertToLogical( - GetWritingMode(), Direction(), - line_box_fragment.Size(), - line_box_child->Size()); + if (line_box_child->GetLayoutObject() == object) { + return child.offset + line_box_child.Offset().ConvertToLogical( + GetWritingMode(), Direction(), + line_box_fragment.Size(), + line_box_child->Size()); } } } } NOTREACHED(); - return NGLogicalOffset(); + return LogicalOffset(); } NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddOutOfFlowChildCandidate( NGBlockNode child, - const NGLogicalOffset& child_offset, + const LogicalOffset& child_offset, base::Optional<TextDirection> container_direction) { DCHECK(child); DCHECK(layout_object_ && !layout_object_->IsLayoutInline() || @@ -188,7 +212,7 @@ NGContainerFragmentBuilder::AddOutOfFlowChildCandidate( oof_positioned_candidates_.push_back(NGOutOfFlowPositionedCandidate( NGOutOfFlowPositionedDescendant( child, NGStaticPosition::Create(GetWritingMode(), direction, - NGPhysicalOffset())), + PhysicalOffset())), child_offset)); return *this; @@ -212,12 +236,11 @@ void NGContainerFragmentBuilder::GetAndClearOutOfFlowDescendantCandidates( DCHECK_GE(InlineSize(), LayoutUnit()); DCHECK_GE(BlockSize(), LayoutUnit()); - NGPhysicalSize builder_physical_size = - ToNGPhysicalSize(Size(), GetWritingMode()); + PhysicalSize builder_physical_size = ToPhysicalSize(Size(), GetWritingMode()); for (NGOutOfFlowPositionedCandidate& candidate : oof_positioned_candidates_) { - NGPhysicalOffset child_offset = candidate.child_offset.ConvertToPhysical( - GetWritingMode(), Direction(), builder_physical_size, NGPhysicalSize()); + PhysicalOffset child_offset = candidate.child_offset.ConvertToPhysical( + GetWritingMode(), Direction(), builder_physical_size, PhysicalSize()); NGStaticPosition builder_relative_position; builder_relative_position.type = candidate.descendant.static_position.type; @@ -230,21 +253,20 @@ void NGContainerFragmentBuilder::GetAndClearOutOfFlowDescendantCandidates( // // This checks if the object creating this box will be the container for // the given descendant. - const LayoutObject* inline_container = + const LayoutInline* inline_container = candidate.descendant.inline_container; - if (!inline_container && layout_object_ && - layout_object_->IsLayoutInline() && - layout_object_->CanContainOutOfFlowPositionedElement( - candidate.descendant.node.Style().GetPosition())) - inline_container = layout_object_; - + if (IsInlineContainerForDescendant(candidate.descendant, layout_object_)) { + inline_container = ToLayoutInline(layout_object_); + } descendant_candidates->push_back(NGOutOfFlowPositionedDescendant( candidate.descendant.node, builder_relative_position, - inline_container)); - NGLogicalOffset container_offset = + inline_container ? ToLayoutInline(inline_container->ContinuationRoot()) + : nullptr)); + + LogicalOffset container_offset = builder_relative_position.offset.ConvertToLogical( GetWritingMode(), Direction(), builder_physical_size, - NGPhysicalSize()); + PhysicalSize()); candidate.descendant.node.SaveStaticOffsetForLegacy(container_offset, current_container); } @@ -259,7 +281,7 @@ void NGContainerFragmentBuilder::GetAndClearOutOfFlowDescendantCandidates( oof_positioned_candidates_.Shrink(0); } -#ifndef NDEBUG +#if DCHECK_IS_ON() String NGContainerFragmentBuilder::ToString() const { StringBuilder builder; @@ -267,7 +289,7 @@ String NGContainerFragmentBuilder::ToString() const { InlineSize().ToFloat(), BlockSize().ToFloat(), children_.size()); for (auto& child : children_) { - builder.Append(child->DumpFragmentTree( + builder.Append(child.fragment->DumpFragmentTree( NGPhysicalFragment::DumpAll & ~NGPhysicalFragment::DumpHeaderText)); } return builder.ToString(); |