Files
sousa-gecko/dom/base/TreeIterator.h
T
Masayuki Nakano dc6c60d7f2 Bug 2012637 - part 1: Make ChildIterBase template class to re-implement FlattenedChildIterator for DOM, Flat and FlatForSelection TreeKind r=smaug,dom-core-reviewers,layout-reviewers,emilio
`FlattenedChildIterator` is a non-template class and work only for the
flattened tree (i.e., in the `TreeKind::Flat` mode).

To centralize the implementation to access children from a parent node
in the various kinds of tree except `ShadowIncludingDOM`, this patch
makes it a template class and support the simple DOM (for
`TreeKind::DOM`), the flattened tree (for`TreeKind::Flat`) and also the
flattened tree for selection whose `TreeKind` will be added by the next
patch.

The reason why this patch does not support
`TreeKind::ShadowIncludingDOM` is, it is not clear that which children
should be handled when the parent is a shadow host, i.e., whether the
children of the host or the `ShadowRoot`. Therefore, the caller should
use `ShadowRoot` if the users want to list up the the children from a
host. Then, the code is really clear about what it does.

Differential Revision: https://phabricator.services.mozilla.com/D281303
2026-07-05 23:40:29 +00:00

147 lines
3.9 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TreeIterator_h
#define TreeIterator_h
#include "mozilla/Attributes.h"
#include "nsIContent.h"
/**
* A generic pre-order tree iterator on top of ChildIterator.
*
* See ChildIterator.h for the kind of iterators you can use as the template
* argument for this class.
*/
namespace mozilla {
namespace dom {
template <typename ChildIterator>
class MOZ_STACK_CLASS TreeIterator {
enum class Direction {
Forward,
Backwards,
};
template <Direction aDirection>
nsIContent* GetNextChild(ChildIterator& aIter) {
return aDirection == Direction::Forward ? aIter.GetNextChild()
: aIter.GetPreviousChild();
}
template <Direction>
inline void Advance();
template <Direction>
inline void AdvanceSkippingChildren();
public:
explicit TreeIterator(nsIContent& aRoot) : mRoot(aRoot), mCurrent(&aRoot) {}
nsIContent* GetCurrent() const { return mCurrent; }
// Note that this keeps the iterator state consistent in case of failure.
inline bool Seek(nsIContent&);
inline nsIContent* GetNext();
inline nsIContent* GetNextSkippingChildren();
inline nsIContent* GetPrev();
inline nsIContent* GetPrevSkippingChildren();
private:
using IteratorArray = AutoTArray<ChildIterator, 30>;
nsIContent& mRoot;
nsIContent* mCurrent;
IteratorArray mParentIterators;
};
template <typename ChildIterator>
template <typename TreeIterator<ChildIterator>::Direction aDirection>
inline void TreeIterator<ChildIterator>::AdvanceSkippingChildren() {
while (true) {
if (MOZ_UNLIKELY(mParentIterators.IsEmpty())) {
mCurrent = nullptr;
return;
}
if (nsIContent* nextSibling =
GetNextChild<aDirection>(mParentIterators.LastElement())) {
mCurrent = nextSibling;
return;
}
mParentIterators.RemoveLastElement();
}
}
template <typename ChildIterator>
inline bool TreeIterator<ChildIterator>::Seek(nsIContent& aContent) {
IteratorArray parentIterators;
nsIContent* current = &aContent;
while (current != &mRoot) {
nsIContent* const parent =
nsIContent::FromNodeOrNull(ChildIterator::GetParentNodeOf(*current));
if (!parent) {
return false;
}
ChildIterator children(parent);
if (!children.Seek(current)) {
return false;
}
parentIterators.AppendElement(std::move(children));
current = parent;
}
parentIterators.Reverse();
mParentIterators = std::move(parentIterators);
mCurrent = &aContent;
return true;
}
template <typename ChildIterator>
template <typename TreeIterator<ChildIterator>::Direction aDirection>
inline void TreeIterator<ChildIterator>::Advance() {
MOZ_ASSERT(mCurrent);
const bool startAtBeginning = aDirection == Direction::Forward;
ChildIterator children(mCurrent, startAtBeginning);
if (nsIContent* first = GetNextChild<aDirection>(children)) {
mCurrent = first;
mParentIterators.AppendElement(std::move(children));
return;
}
AdvanceSkippingChildren<aDirection>();
}
template <typename ChildIterator>
inline nsIContent* TreeIterator<ChildIterator>::GetNext() {
Advance<Direction::Forward>();
return GetCurrent();
}
template <typename ChildIterator>
inline nsIContent* TreeIterator<ChildIterator>::GetPrev() {
Advance<Direction::Backwards>();
return GetCurrent();
}
template <typename ChildIterator>
inline nsIContent* TreeIterator<ChildIterator>::GetNextSkippingChildren() {
AdvanceSkippingChildren<Direction::Forward>();
return GetCurrent();
}
template <typename ChildIterator>
inline nsIContent* TreeIterator<ChildIterator>::GetPrevSkippingChildren() {
AdvanceSkippingChildren<Direction::Backwards>();
return GetCurrent();
}
} // namespace dom
} // namespace mozilla
#endif