| // 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. |
| |
| #ifndef NGContainerFragmentBuilder_h |
| #define NGContainerFragmentBuilder_h |
| |
| #include "base/memory/scoped_refptr.h" |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/layout/geometry/logical_size.h" |
| #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h" |
| #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h" |
| #include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h" |
| #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" |
| #include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_break_appeal.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_early_break.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_link.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h" |
| #include "third_party/blink/renderer/core/style/computed_style.h" |
| #include "third_party/blink/renderer/platform/text/text_direction.h" |
| #include "third_party/blink/renderer/platform/text/writing_mode.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" |
| |
| namespace blink { |
| |
| class NGExclusionSpace; |
| class NGPhysicalFragment; |
| |
| class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder { |
| STACK_ALLOCATED(); |
| |
| public: |
| struct ChildWithOffset { |
| DISALLOW_NEW(); |
| ChildWithOffset(LogicalOffset offset, |
| scoped_refptr<const NGPhysicalFragment> fragment) |
| : offset(offset), fragment(std::move(fragment)) {} |
| |
| // We store logical offsets (instead of the final physical), as we can't |
| // convert into the physical coordinate space until we know our final size. |
| LogicalOffset offset; |
| scoped_refptr<const NGPhysicalFragment> fragment; |
| }; |
| typedef Vector<ChildWithOffset, 4> ChildrenVector; |
| |
| LayoutUnit BfcLineOffset() const { return bfc_line_offset_; } |
| void SetBfcLineOffset(LayoutUnit bfc_line_offset) { |
| bfc_line_offset_ = bfc_line_offset; |
| } |
| |
| // The BFC block-offset is where this fragment was positioned within the BFC. |
| // If it is not set, this fragment may be placed anywhere within the BFC. |
| const base::Optional<LayoutUnit>& BfcBlockOffset() const { |
| return bfc_block_offset_; |
| } |
| void SetBfcBlockOffset(LayoutUnit bfc_block_offset) { |
| bfc_block_offset_ = bfc_block_offset; |
| } |
| void ResetBfcBlockOffset() { bfc_block_offset_.reset(); } |
| |
| void SetEndMarginStrut(const NGMarginStrut& end_margin_strut) { |
| end_margin_strut_ = end_margin_strut; |
| } |
| |
| void SetExclusionSpace(NGExclusionSpace&& exclusion_space) { |
| exclusion_space_ = std::move(exclusion_space); |
| } |
| |
| const NGUnpositionedListMarker& UnpositionedListMarker() const { |
| return unpositioned_list_marker_; |
| } |
| void SetUnpositionedListMarker(const NGUnpositionedListMarker& marker) { |
| DCHECK(!unpositioned_list_marker_ || !marker); |
| unpositioned_list_marker_ = marker; |
| } |
| |
| void AddChild(const NGPhysicalContainerFragment&, |
| const LogicalOffset&, |
| const LayoutInline* inline_container = nullptr); |
| |
| void AddChild(scoped_refptr<const NGPhysicalTextFragment> child, |
| const LogicalOffset& offset) { |
| AddChildInternal(child, offset); |
| } |
| |
| const ChildrenVector& Children() const { return children_; } |
| |
| // Returns offset for given child. DCHECK if child not found. |
| // Warning: Do not call unless necessary. |
| LogicalOffset GetChildOffset(const LayoutObject* child) const; |
| |
| // Builder has non-trivial OOF-positioned methods. |
| // They are intended to be used by a layout algorithm like this: |
| // |
| // Part 1: layout algorithm positions in-flow children. |
| // out-of-flow children, and out-of-flow descendants of fragments |
| // are stored inside builder. |
| // |
| // for (child : children) |
| // if (child->position == (Absolute or Fixed)) |
| // builder->AddOutOfFlowChildCandidate(child); |
| // else |
| // fragment = child->Layout() |
| // builder->AddChild(fragment) |
| // end |
| // |
| // builder->SetSize |
| // |
| // Part 2: Out-of-flow layout part positions OOF-positioned nodes. |
| // |
| // NGOutOfFlowLayoutPart(container_style, builder).Run(); |
| // |
| // See layout part for builder interaction. |
| // |
| // @param direction: default candidate direction is builder's direction. |
| // Pass in direction if candidates direction does not match. |
| void AddOutOfFlowChildCandidate( |
| NGBlockNode, |
| const LogicalOffset& child_offset, |
| base::Optional<TextDirection> container_direction = base::nullopt); |
| |
| void AddOutOfFlowDescendant( |
| const NGLogicalOutOfFlowPositionedNode& descendant); |
| |
| void SwapOutOfFlowPositionedCandidates( |
| Vector<NGLogicalOutOfFlowPositionedNode>* candidates, |
| const LayoutObject* current_container); |
| |
| bool HasOutOfFlowPositionedCandidates() const { |
| return !oof_positioned_candidates_.IsEmpty(); |
| } |
| |
| // This method should only be used within the inline layout algorithm. It is |
| // used to convert all OOF-positioned candidates to descendants. |
| // |
| // During the inline layout algorithm, we don't have enough information to |
| // position OOF candidates yet, (as a containing box may be split over |
| // multiple lines), instead we bubble all the descendants up to the parent |
| // block layout algorithm, to perform the final OOF layout and positioning. |
| void MoveOutOfFlowDescendantCandidatesToDescendants() { |
| SwapOutOfFlowPositionedCandidates(&oof_positioned_descendants_, nullptr); |
| } |
| |
| void SetIsSelfCollapsing() { is_self_collapsing_ = true; } |
| |
| void SetIsPushedByFloats() { is_pushed_by_floats_ = true; } |
| bool IsPushedByFloats() const { return is_pushed_by_floats_; } |
| |
| void ResetAdjoiningObjectTypes() { |
| adjoining_object_types_ = kAdjoiningNone; |
| has_adjoining_object_descendants_ = false; |
| } |
| void AddAdjoiningObjectTypes(NGAdjoiningObjectTypes adjoining_object_types) { |
| adjoining_object_types_ |= adjoining_object_types; |
| has_adjoining_object_descendants_ |= adjoining_object_types; |
| } |
| void SetAdjoiningObjectTypes(NGAdjoiningObjectTypes adjoining_object_types) { |
| adjoining_object_types_ = adjoining_object_types; |
| } |
| NGAdjoiningObjectTypes AdjoiningObjectTypes() const { |
| return adjoining_object_types_; |
| } |
| |
| void SetHasBlockFragmentation() { has_block_fragmentation_ = true; } |
| |
| // Set for any node that establishes a fragmentation context, such as multicol |
| // containers. |
| void SetIsBlockFragmentationContextRoot() { |
| is_fragmentation_context_root_ = true; |
| } |
| |
| const NGConstraintSpace* ConstraintSpace() const { return space_; } |
| |
| #if DCHECK_IS_ON() |
| String ToString() const; |
| #endif |
| |
| protected: |
| friend class NGPhysicalContainerFragment; |
| friend class NGLayoutResult; |
| |
| NGContainerFragmentBuilder(NGLayoutInputNode node, |
| scoped_refptr<const ComputedStyle> style, |
| const NGConstraintSpace* space, |
| WritingMode writing_mode, |
| TextDirection direction) |
| : NGFragmentBuilder(std::move(style), writing_mode, direction), |
| node_(node), |
| space_(space) { |
| layout_object_ = node.GetLayoutBox(); |
| } |
| |
| void AddChildInternal(scoped_refptr<const NGPhysicalFragment>, |
| const LogicalOffset&); |
| |
| NGLayoutInputNode node_; |
| const NGConstraintSpace* space_; |
| |
| LayoutUnit bfc_line_offset_; |
| base::Optional<LayoutUnit> bfc_block_offset_; |
| NGMarginStrut end_margin_strut_; |
| NGExclusionSpace exclusion_space_; |
| |
| Vector<NGLogicalOutOfFlowPositionedNode> oof_positioned_candidates_; |
| Vector<NGLogicalOutOfFlowPositionedNode> oof_positioned_descendants_; |
| |
| NGUnpositionedListMarker unpositioned_list_marker_; |
| |
| ChildrenVector children_; |
| |
| // Only used by the NGBoxFragmentBuilder subclass, but defined here to avoid |
| // a virtual function call. |
| NGBreakTokenVector child_break_tokens_; |
| NGBreakTokenVector inline_break_tokens_; |
| |
| scoped_refptr<const NGEarlyBreak> early_break_; |
| NGBreakAppeal break_appeal_ = kBreakAppealLastResort; |
| |
| NGAdjoiningObjectTypes adjoining_object_types_ = kAdjoiningNone; |
| bool has_adjoining_object_descendants_ = false; |
| |
| bool is_self_collapsing_ = false; |
| bool is_pushed_by_floats_ = false; |
| bool is_legacy_layout_root_ = false; |
| |
| bool has_floating_descendants_ = false; |
| bool has_orthogonal_flow_roots_ = false; |
| bool has_descendant_that_depends_on_percentage_block_size_ = false; |
| bool has_block_fragmentation_ = false; |
| bool is_fragmentation_context_root_ = false; |
| bool may_have_descendant_above_block_start_ = false; |
| }; |
| |
| } // namespace blink |
| |
| WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS( |
| blink::NGContainerFragmentBuilder::ChildWithOffset) |
| |
| #endif // NGContainerFragmentBuilder |