diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h')
-rw-r--r-- | chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h new file mode 100644 index 00000000000..c4927f0acad --- /dev/null +++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h @@ -0,0 +1,141 @@ +// Copyright 2020 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_FRAGMENT_CHILD_ITERATOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_ + +#include "base/containers/span.h" +#include "base/optional.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" +#include "third_party/blink/renderer/core/layout/ng/ng_link.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" + +namespace blink { + +class LayoutObject; +class NGBlockBreakToken; + +// Iterator for children of a box fragment. Supports fragment items and break +// tokens. To advance to the next sibling, call |Advance()|. To descend into +// children of the current child, call |Descend()|. +// +// Using this class requires LayoutNGFragmentItem to be enabled. While fragment +// items are in a flat list representing the contents of an inline formatting +// context, the iterator will to a certain extent restore the object hierarchy, +// so that we can calculate the global offset of children of a relatively +// positioned inline correctly. +class CORE_EXPORT NGFragmentChildIterator { + STACK_ALLOCATED(); + + public: + explicit NGFragmentChildIterator( + const NGPhysicalBoxFragment& parent, + const NGBlockBreakToken* parent_break_token = nullptr); + + // Create a child iterator for the current child. + NGFragmentChildIterator Descend() const; + + // Move to the next sibling. Return false if there's no next sibling. Once + // false is returned, this object is in an unusable state, with the exception + // that calling IsAtEnd() is allowed. + bool Advance() { + if (current_.cursor_) + return AdvanceWithCursor(); + return AdvanceChildFragment(); + } + + bool IsAtEnd() { + if (current_.cursor_) + return !*current_.cursor_; + DCHECK(parent_fragment_); + const auto children = parent_fragment_->Children(); + return child_fragment_idx_ >= children.size(); + } + + class Current { + friend class NGFragmentChildIterator; + + public: + // Return the current NGLink. Note that its offset is relative to the inline + // formatting context root, if the fragment / item participates in one. + const NGLink& Link() const { return link_; } + + const NGPhysicalBoxFragment* BoxFragment() const { + return To<NGPhysicalBoxFragment>(link_.fragment); + } + const NGFragmentItem* FragmentItem() const { + if (!cursor_) + return nullptr; + return cursor_->CurrentItem(); + } + + // Get the incoming break token for the current child, i.e. the context at + // which layout of this child's node was resumed. Note that for text and + // non-atomic inlines this will be the incoming block break token to the + // inline formatting context root. For monolithic content, no break token + // will be returned (since such content isn't considered to participate in a + // fragmentation context). + const NGBlockBreakToken* BlockBreakToken() const { + if (LIKELY(!block_break_token_)) + return nullptr; + if (link_.fragment) { + // Don't pass the break token into monolithic content. + if (link_.fragment->IsMonolithic()) + return nullptr; + // If the break token we've found is from a fragmentainer, it's only to + // be used by a subsequent fragmentainer. Other fragment types (such as + // column spanners) need to ignore it. + if (break_token_for_fragmentainer_only_ && + !link_.fragment->IsColumnBox()) + return nullptr; + } + return block_break_token_; + } + + const LayoutObject* GetLayoutObject() const { + if (const NGFragmentItem* item = FragmentItem()) + return item->GetLayoutObject(); + return BoxFragment()->GetLayoutObject(); + } + + private: + NGLink link_; + base::Optional<NGInlineCursor> cursor_; + const NGBlockBreakToken* block_break_token_ = nullptr; + bool break_token_for_fragmentainer_only_ = false; + }; + + const Current& GetCurrent() const { return current_; } + const Current& operator*() const { return current_; } + const Current* operator->() const { return ¤t_; } + + private: + NGFragmentChildIterator( + const NGInlineCursor& parent, + const NGBlockBreakToken* parent_break_token, + base::span<const NGBreakToken* const> child_break_tokens); + + bool AdvanceChildFragment(); + void UpdateSelfFromFragment( + const NGPhysicalBoxFragment* previous_fragment = nullptr); + + bool AdvanceWithCursor(); + void UpdateSelfFromCursor(); + void SkipToBoxFragment(); + void SkipToBlockBreakToken(); + + const NGPhysicalBoxFragment* parent_fragment_ = nullptr; + const NGBlockBreakToken* parent_break_token_ = nullptr; + Current current_; + base::span<const NGBreakToken* const> child_break_tokens_; + wtf_size_t child_fragment_idx_ = 0; + wtf_size_t child_break_token_idx_ = 0; + bool is_fragmentation_context_root_ = false; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_ |