blob: 05d65e3ab7f69ce7e5938ecd36e2d78600f3eecc [file] [log] [blame] [edit]
// Copyright 2017 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#ifndef XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_
#define XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_
#include <type_traits>
#include "core/fxcrt/unowned_ptr.h"
#include "v8/include/cppgc/macros.h"
#include "v8/include/cppgc/type-traits.h"
template <class NodeType,
class TraverseStrategy,
typename HolderType = std::conditional_t<
cppgc::IsGarbageCollectedOrMixinTypeV<NodeType>,
NodeType*,
UnownedPtr<NodeType>>>
class CXFA_NodeIteratorTemplate {
CPPGC_STACK_ALLOCATED(); // Allows Raw/Unowned |HolderType|.
public:
explicit CXFA_NodeIteratorTemplate(NodeType* pRoot)
: root_(pRoot), current_(pRoot) {}
NodeType* GetRoot() const { return static_cast<NodeType*>(root_); }
NodeType* GetCurrent() const { return static_cast<NodeType*>(current_); }
void Reset() { current_ = root_; }
bool SetCurrent(NodeType* pNode) {
if (!RootReachableFromNode(pNode)) {
current_ = nullptr;
return false;
}
current_ = pNode;
return true;
}
NodeType* MoveToPrev() {
if (!root_) {
return nullptr;
}
if (!current_) {
current_ = LastDescendant(static_cast<NodeType*>(root_));
return static_cast<NodeType*>(current_);
}
NodeType* pSibling =
PreviousSiblingWithinSubtree(static_cast<NodeType*>(current_));
if (pSibling) {
current_ = LastDescendant(pSibling);
return static_cast<NodeType*>(current_);
}
NodeType* pParent = ParentWithinSubtree(static_cast<NodeType*>(current_));
if (pParent) {
current_ = pParent;
}
return pParent;
}
NodeType* MoveToNext() {
if (!root_ || !current_) {
return nullptr;
}
NodeType* pChild =
TraverseStrategy::GetFirstChild(static_cast<NodeType*>(current_));
if (pChild) {
current_ = pChild;
return pChild;
}
return SkipChildrenAndMoveToNext();
}
NodeType* SkipChildrenAndMoveToNext() {
if (!root_) {
return nullptr;
}
NodeType* pNode = static_cast<NodeType*>(current_);
while (pNode) {
NodeType* pSibling = NextSiblingWithinSubtree(pNode);
if (pSibling) {
current_ = pSibling;
return pSibling;
}
pNode = ParentWithinSubtree(pNode);
}
current_ = nullptr;
return nullptr;
}
private:
bool RootReachableFromNode(NodeType* pNode) {
return pNode && (pNode == root_ ||
RootReachableFromNode(TraverseStrategy::GetParent(pNode)));
}
NodeType* ParentWithinSubtree(NodeType* pNode) {
return pNode && pNode != root_ ? TraverseStrategy::GetParent(pNode)
: nullptr;
}
NodeType* NextSiblingWithinSubtree(NodeType* pNode) {
return pNode != root_ ? TraverseStrategy::GetNextSibling(pNode) : nullptr;
}
NodeType* PreviousSiblingWithinSubtree(NodeType* pNode) {
NodeType* pParent = ParentWithinSubtree(pNode);
if (!pParent) {
return nullptr;
}
NodeType* pCurrent = TraverseStrategy::GetFirstChild(pParent);
NodeType* pPrevious = nullptr;
while (pCurrent != pNode) {
pPrevious = pCurrent;
pCurrent = TraverseStrategy::GetNextSibling(pCurrent);
}
return pPrevious;
}
NodeType* LastChild(NodeType* pNode) {
NodeType* pPrevious = nullptr;
NodeType* pChild = TraverseStrategy::GetFirstChild(pNode);
while (pChild) {
pPrevious = pChild;
pChild = NextSiblingWithinSubtree(pChild);
}
return pPrevious;
}
NodeType* LastDescendant(NodeType* pNode) {
NodeType* pChild = LastChild(pNode);
return pChild ? LastDescendant(pChild) : pNode;
}
HolderType root_;
HolderType current_;
};
#endif // XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_