|  | // 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_ |