blob: 921533ed3d70ae6d6fd1a4c945d784be727a10c4 [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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_PHYSICAL_CONTAINER_FRAGMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_PHYSICAL_CONTAINER_FRAGMENT_H_
#include <iterator>
#include "base/containers/span.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_link.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class NGContainerFragmentBuilder;
class NGFragmentItem;
struct NGPhysicalOutOfFlowPositionedNode;
enum class NGOutlineType;
class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
public:
// Same as |base::span<const NGLink>|, except that:
// * Each |NGLink| has the latest generation of post-layout. See
// |NGPhysicalFragment::UpdatedFragment()| for more details.
// * The iterator skips fragments for destroyed or moved |LayoutObject|.
class PostLayoutChildLinkList {
public:
PostLayoutChildLinkList(wtf_size_t count, const NGLink* buffer)
: count_(count), buffer_(buffer) {}
class ConstIterator
: public std::iterator<std::input_iterator_tag, NGLink> {
STACK_ALLOCATED();
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = NGLink;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
ConstIterator(const NGLink* current, wtf_size_t size)
: current_(current), end_(current + size) {
SkipInvalidAndSetPostLayout();
}
const NGLink& operator*() const { return post_layout_; }
const NGLink* operator->() const { return &post_layout_; }
ConstIterator& operator++() {
++current_;
SkipInvalidAndSetPostLayout();
return *this;
}
bool operator==(const ConstIterator& other) const {
return current_ == other.current_;
}
bool operator!=(const ConstIterator& other) const {
return current_ != other.current_;
}
private:
void SkipInvalidAndSetPostLayout() {
for (; current_ != end_; ++current_) {
const NGPhysicalFragment* fragment = current_->fragment;
if (UNLIKELY(fragment->IsLayoutObjectDestroyedOrMoved()))
continue;
if (const NGPhysicalFragment* post_layout = fragment->PostLayout()) {
post_layout_.fragment = post_layout;
post_layout_.offset = current_->offset;
return;
}
}
}
const NGLink* current_;
const NGLink* end_;
NGLink post_layout_;
};
using const_iterator = ConstIterator;
const_iterator begin() const { return const_iterator(buffer_, count_); }
const_iterator end() const { return const_iterator(buffer_ + count_, 0); }
wtf_size_t size() const { return count_; }
bool empty() const { return count_ == 0; }
private:
wtf_size_t count_;
const NGLink* buffer_;
};
~NGPhysicalContainerFragment();
const NGBreakToken* BreakToken() const { return break_token_.get(); }
// Returns the children of |this|.
//
// Note, children in this collection maybe old generations. Items in this
// collection are safe, but their children (grandchildren of |this|) maybe
// from deleted nodes or LayoutObjects. Also see |PostLayoutChildren()|.
base::span<const NGLink> Children() const {
return base::make_span(buffer_, num_children_);
}
// Similar to |Children()| but all children are the latest generation of
// post-layout, and therefore all descendants are safe.
PostLayoutChildLinkList PostLayoutChildren() const {
return PostLayoutChildLinkList(num_children_, buffer_);
}
// Returns true if we have any floating descendants which need to be
// traversed during the float paint phase.
bool HasFloatingDescendantsForPaint() const {
return has_floating_descendants_for_paint_;
}
// Returns true if we have any adjoining-object descendants (floats, or
// inline-level OOF-positioned objects).
bool HasAdjoiningObjectDescendants() const {
return has_adjoining_object_descendants_;
}
// Returns true if we aren't able to re-use this fragment if the
// |NGConstraintSpace::PercentageResolutionBlockSize| changes.
bool DependsOnPercentageBlockSize() const {
return depends_on_percentage_block_size_;
}
bool HasOutOfFlowPositionedDescendants() const {
DCHECK(!oof_positioned_descendants_ ||
!oof_positioned_descendants_->IsEmpty());
return oof_positioned_descendants_.get();
}
base::span<NGPhysicalOutOfFlowPositionedNode> OutOfFlowPositionedDescendants()
const {
if (!HasOutOfFlowPositionedDescendants())
return base::span<NGPhysicalOutOfFlowPositionedNode>();
return {oof_positioned_descendants_->data(),
oof_positioned_descendants_->size()};
}
// This exposes a mutable part of the fragment for |NGOutOfFlowLayoutPart|.
class MutableChildrenForOutOfFlow final {
STACK_ALLOCATED();
protected:
friend class NGOutOfFlowLayoutPart;
base::span<NGLink> Children() const {
return base::make_span(buffer_, num_children_);
}
private:
friend class NGPhysicalContainerFragment;
MutableChildrenForOutOfFlow(const NGLink* buffer, wtf_size_t num_children)
: buffer_(const_cast<NGLink*>(buffer)), num_children_(num_children) {}
NGLink* buffer_;
wtf_size_t num_children_;
};
MutableChildrenForOutOfFlow GetMutableChildrenForOutOfFlow() const {
return MutableChildrenForOutOfFlow(buffer_, num_children_);
}
protected:
// block_or_line_writing_mode is used for converting the child offsets.
NGPhysicalContainerFragment(NGContainerFragmentBuilder*,
WritingMode block_or_line_writing_mode,
NGLink* buffer,
NGFragmentType,
unsigned sub_type);
NGPhysicalContainerFragment(const NGPhysicalContainerFragment& other,
bool recalculate_layout_overflow,
NGLink* buffer);
void AddScrollableOverflowForInlineChild(
const NGPhysicalBoxFragment& container,
const ComputedStyle& container_style,
const NGFragmentItem& line,
bool has_hanging,
const NGInlineCursor& cursor,
TextHeightType height_type,
PhysicalRect* overflow) const;
static void AdjustScrollableOverflowForHanging(
const PhysicalRect& rect,
const WritingMode container_writing_mode,
PhysicalRect* overflow);
void AddOutlineRectsForNormalChildren(
Vector<PhysicalRect>* outline_rects,
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
const LayoutBoxModelObject* containing_block) const;
void AddOutlineRectsForCursor(Vector<PhysicalRect>* outline_rects,
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
const LayoutBoxModelObject* containing_block,
NGInlineCursor* cursor) const;
void AddOutlineRectsForDescendant(
const NGLink& descendant,
Vector<PhysicalRect>* rects,
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
const LayoutBoxModelObject* containing_block) const;
static bool DependsOnPercentageBlockSize(const NGContainerFragmentBuilder&);
wtf_size_t num_children_;
scoped_refptr<const NGBreakToken> break_token_;
const std::unique_ptr<Vector<NGPhysicalOutOfFlowPositionedNode>>
oof_positioned_descendants_;
// Because flexible arrays need to be the last member in a class, the actual
// storage is in the subclass and we just keep a pointer to it here.
const NGLink* buffer_;
};
template <>
struct DowncastTraits<NGPhysicalContainerFragment> {
static bool AllowFrom(const NGPhysicalFragment& fragment) {
return fragment.IsContainer();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_PHYSICAL_CONTAINER_FRAGMENT_H_