From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- dom/base/TreeIterator.h | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 dom/base/TreeIterator.h (limited to 'dom/base/TreeIterator.h') diff --git a/dom/base/TreeIterator.h b/dom/base/TreeIterator.h new file mode 100644 index 0000000000..67c8457ef0 --- /dev/null +++ b/dom/base/TreeIterator.h @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 +class MOZ_STACK_CLASS TreeIterator { + enum class Direction { + Forward, + Backwards, + }; + + template + nsIContent* GetNextChild(ChildIterator& aIter) { + return aDirection == Direction::Forward ? aIter.GetNextChild() + : aIter.GetPreviousChild(); + } + + template + inline void Advance(); + template + 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; + + nsIContent& mRoot; + nsIContent* mCurrent; + IteratorArray mParentIterators; +}; + +template +template ::Direction aDirection> +inline void TreeIterator::AdvanceSkippingChildren() { + while (true) { + if (MOZ_UNLIKELY(mParentIterators.IsEmpty())) { + mCurrent = nullptr; + return; + } + + if (nsIContent* nextSibling = + GetNextChild(mParentIterators.LastElement())) { + mCurrent = nextSibling; + return; + } + mParentIterators.RemoveLastElement(); + } +} + +template +inline bool TreeIterator::Seek(nsIContent& aContent) { + IteratorArray parentIterators; + nsIContent* current = &aContent; + while (current != &mRoot) { + nsIContent* parent = ChildIterator::GetParent(*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 +template ::Direction aDirection> +inline void TreeIterator::Advance() { + MOZ_ASSERT(mCurrent); + const bool startAtBeginning = aDirection == Direction::Forward; + ChildIterator children(mCurrent, startAtBeginning); + if (nsIContent* first = GetNextChild(children)) { + mCurrent = first; + mParentIterators.AppendElement(std::move(children)); + return; + } + + AdvanceSkippingChildren(); +} + +template +inline nsIContent* TreeIterator::GetNext() { + Advance(); + return GetCurrent(); +} + +template +inline nsIContent* TreeIterator::GetPrev() { + Advance(); + return GetCurrent(); +} + +template +inline nsIContent* TreeIterator::GetNextSkippingChildren() { + AdvanceSkippingChildren(); + return GetCurrent(); +} + +template +inline nsIContent* TreeIterator::GetPrevSkippingChildren() { + AdvanceSkippingChildren(); + return GetCurrent(); +} + +} // namespace dom +} // namespace mozilla + +#endif -- cgit v1.2.3