131 lines
3.7 KiB
C++
131 lines
3.7 KiB
C++
// 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 "core/fxcrt/unowned_ptr.h"
|
|
#include "v8/include/cppgc/macros.h"
|
|
|
|
template <class NodeType,
|
|
class TraverseStrategy,
|
|
typename HolderType = UnownedPtr<NodeType>>
|
|
class CXFA_NodeIteratorTemplate {
|
|
CPPGC_STACK_ALLOCATED(); // Allows Raw/Unowned |HolderType|.
|
|
|
|
public:
|
|
explicit CXFA_NodeIteratorTemplate(NodeType* pRoot)
|
|
: m_pRoot(pRoot), m_pCurrent(pRoot) {}
|
|
|
|
NodeType* GetRoot() const { return static_cast<NodeType*>(m_pRoot); }
|
|
NodeType* GetCurrent() const { return static_cast<NodeType*>(m_pCurrent); }
|
|
|
|
void Reset() { m_pCurrent = m_pRoot; }
|
|
bool SetCurrent(NodeType* pNode) {
|
|
if (!RootReachableFromNode(pNode)) {
|
|
m_pCurrent = nullptr;
|
|
return false;
|
|
}
|
|
m_pCurrent = pNode;
|
|
return true;
|
|
}
|
|
|
|
NodeType* MoveToPrev() {
|
|
if (!m_pRoot)
|
|
return nullptr;
|
|
if (!m_pCurrent) {
|
|
m_pCurrent = LastDescendant(static_cast<NodeType*>(m_pRoot));
|
|
return static_cast<NodeType*>(m_pCurrent);
|
|
}
|
|
NodeType* pSibling =
|
|
PreviousSiblingWithinSubtree(static_cast<NodeType*>(m_pCurrent));
|
|
if (pSibling) {
|
|
m_pCurrent = LastDescendant(pSibling);
|
|
return static_cast<NodeType*>(m_pCurrent);
|
|
}
|
|
NodeType* pParent = ParentWithinSubtree(static_cast<NodeType*>(m_pCurrent));
|
|
if (pParent)
|
|
m_pCurrent = pParent;
|
|
return pParent;
|
|
}
|
|
|
|
NodeType* MoveToNext() {
|
|
if (!m_pRoot || !m_pCurrent)
|
|
return nullptr;
|
|
NodeType* pChild =
|
|
TraverseStrategy::GetFirstChild(static_cast<NodeType*>(m_pCurrent));
|
|
if (pChild) {
|
|
m_pCurrent = pChild;
|
|
return pChild;
|
|
}
|
|
return SkipChildrenAndMoveToNext();
|
|
}
|
|
|
|
NodeType* SkipChildrenAndMoveToNext() {
|
|
if (!m_pRoot)
|
|
return nullptr;
|
|
NodeType* pNode = static_cast<NodeType*>(m_pCurrent);
|
|
while (pNode) {
|
|
NodeType* pSibling = NextSiblingWithinSubtree(pNode);
|
|
if (pSibling) {
|
|
m_pCurrent = pSibling;
|
|
return pSibling;
|
|
}
|
|
pNode = ParentWithinSubtree(pNode);
|
|
}
|
|
m_pCurrent = nullptr;
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
bool RootReachableFromNode(NodeType* pNode) {
|
|
return pNode && (pNode == m_pRoot ||
|
|
RootReachableFromNode(TraverseStrategy::GetParent(pNode)));
|
|
}
|
|
|
|
NodeType* ParentWithinSubtree(NodeType* pNode) {
|
|
return pNode && pNode != m_pRoot ? TraverseStrategy::GetParent(pNode)
|
|
: nullptr;
|
|
}
|
|
|
|
NodeType* NextSiblingWithinSubtree(NodeType* pNode) {
|
|
return pNode != m_pRoot ? 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 m_pRoot;
|
|
HolderType m_pCurrent;
|
|
};
|
|
|
|
#endif // XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_
|