blob: 63e82a7cfbf83628d2a549bb5f32b6a4c2dc1e00 [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.
#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/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_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.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_descendant.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.h"
namespace blink {
class NGExclusionSpace;
class NGLayoutResult;
class NGPhysicalFragment;
class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
STACK_ALLOCATED();
public:
typedef Vector<scoped_refptr<const NGPhysicalFragment>, 16> ChildrenVector;
typedef Vector<NGLogicalOffset, 16> OffsetVector;
LayoutUnit BfcLineOffset() const { return bfc_line_offset_; }
NGContainerFragmentBuilder& SetBfcLineOffset(LayoutUnit bfc_line_offset) {
bfc_line_offset_ = bfc_line_offset;
return *this;
}
// The NGBfcOffset 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_;
}
NGContainerFragmentBuilder& SetBfcBlockOffset(LayoutUnit bfc_block_offset) {
bfc_block_offset_ = bfc_block_offset;
return *this;
}
NGContainerFragmentBuilder& ResetBfcBlockOffset() {
bfc_block_offset_.reset();
return *this;
}
NGContainerFragmentBuilder& SetEndMarginStrut(
const NGMarginStrut& end_margin_strut) {
end_margin_strut_ = end_margin_strut;
return *this;
}
NGContainerFragmentBuilder& SetExclusionSpace(
NGExclusionSpace&& exclusion_space) {
exclusion_space_ = std::move(exclusion_space);
return *this;
}
const NGUnpositionedListMarker& UnpositionedListMarker() const {
return unpositioned_list_marker_;
}
NGContainerFragmentBuilder& SetUnpositionedListMarker(
const NGUnpositionedListMarker& marker) {
DCHECK(!unpositioned_list_marker_ || !marker);
unpositioned_list_marker_ = marker;
return *this;
}
NGContainerFragmentBuilder& AddChild(const NGLayoutResult&,
const NGLogicalOffset&);
// This version of AddChild will not propagate floats/out_of_flow.
// Use the AddChild(NGLayoutResult) variant if NGLayoutResult is available.
NGContainerFragmentBuilder& AddChild(scoped_refptr<const NGPhysicalFragment>,
const NGLogicalOffset&);
const ChildrenVector& Children() const { return children_; }
// Returns offset for given child. DCHECK if child not found.
// Warning: Do not call unless necessary.
NGLogicalOffset GetChildOffset(const LayoutObject* child);
// Builder has non-trivial out-of-flow descendant methods.
// These methods are building blocks for implementation of
// out-of-flow descendants by layout algorithms.
//
// They are intended to be used by 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 out-of-flow descendants.
//
// 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.
NGContainerFragmentBuilder& AddOutOfFlowChildCandidate(
NGBlockNode,
const NGLogicalOffset& child_offset,
base::Optional<TextDirection> container_direction = base::nullopt);
NGContainerFragmentBuilder& AddOutOfFlowDescendant(
NGOutOfFlowPositionedDescendant descendant);
void GetAndClearOutOfFlowDescendantCandidates(
Vector<NGOutOfFlowPositionedDescendant>* descendant_candidates,
const LayoutObject* container);
bool HasOutOfFlowDescendantCandidates() const {
return !oof_positioned_candidates_.IsEmpty();
}
// This method should only be used within the inline layout algorithm. It is
// used to convert all OOF descendant 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();
NGContainerFragmentBuilder& SetIsPushedByFloats() {
is_pushed_by_floats_ = true;
return *this;
}
bool IsPushedByFloats() const { return is_pushed_by_floats_; }
NGContainerFragmentBuilder& ResetAdjoiningFloatTypes() {
adjoining_floats_ = kFloatTypeNone;
return *this;
}
NGContainerFragmentBuilder& AddAdjoiningFloatTypes(NGFloatTypes floats) {
adjoining_floats_ |= floats;
return *this;
}
NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
#ifndef NDEBUG
String ToString() const;
#endif
protected:
// An out-of-flow positioned-candidate is a temporary data structure used
// within the NGBoxFragmentBuilder.
//
// A positioned-candidate can be:
// 1. A direct out-of-flow positioned child. The child_offset is (0,0).
// 2. A fragment containing an out-of-flow positioned-descendant. The
// child_offset in this case is the containing fragment's offset.
//
// The child_offset is stored as a NGLogicalOffset as the physical offset
// cannot be computed until we know the current fragment's size.
//
// When returning the positioned-candidates (from
// GetAndClearOutOfFlowDescendantCandidates), the NGBoxFragmentBuilder will
// convert the positioned-candidate to a positioned-descendant using the
// physical size the fragment builder.
struct NGOutOfFlowPositionedCandidate {
NGOutOfFlowPositionedDescendant descendant;
NGLogicalOffset child_offset; // Logical offset of child's top left vertex.
NGOutOfFlowPositionedCandidate(NGOutOfFlowPositionedDescendant descendant,
NGLogicalOffset child_offset)
: descendant(descendant), child_offset(child_offset) {}
};
NGContainerFragmentBuilder(scoped_refptr<const ComputedStyle> style,
WritingMode writing_mode,
TextDirection direction)
: NGFragmentBuilder(std::move(style), writing_mode, direction) {}
LayoutUnit bfc_line_offset_;
base::Optional<LayoutUnit> bfc_block_offset_;
NGMarginStrut end_margin_strut_;
NGExclusionSpace exclusion_space_;
Vector<NGOutOfFlowPositionedCandidate> oof_positioned_candidates_;
Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
NGUnpositionedListMarker unpositioned_list_marker_;
ChildrenVector children_;
// Logical offsets for the children. Stored as logical offsets as we can't
// convert to physical offsets until layout of all children has been
// determined.
OffsetVector offsets_;
// Only used by the NGBoxFragmentBuilder subclass, but defined here to avoid
// a virtual function call.
NGBreakTokenVector child_break_tokens_;
NGBreakTokenVector inline_break_tokens_;
NGFloatTypes adjoining_floats_ = kFloatTypeNone;
bool has_last_resort_break_ = false;
bool is_pushed_by_floats_ = false;
bool has_orthogonal_flow_roots_ = false;
friend class NGPhysicalContainerFragment;
};
} // namespace blink
#endif // NGContainerFragmentBuilder