1 // Copyright 2017 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #ifndef XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_ 8 #define XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_ 9 10 template <class NodeType, class TraverseStrategy> 11 class CXFA_NodeIteratorTemplate { 12 public: CXFA_NodeIteratorTemplate(NodeType * pRoot)13 explicit CXFA_NodeIteratorTemplate(NodeType* pRoot) 14 : m_pRoot(pRoot), m_pCurrent(pRoot) {} 15 GetRoot()16 NodeType* GetRoot() const { return m_pRoot; } GetCurrent()17 NodeType* GetCurrent() const { return m_pCurrent; } 18 Reset()19 void Reset() { m_pCurrent = m_pRoot; } SetCurrent(NodeType * pNode)20 bool SetCurrent(NodeType* pNode) { 21 if (!RootReachableFromNode(pNode)) { 22 m_pCurrent = nullptr; 23 return false; 24 } 25 m_pCurrent = pNode; 26 return true; 27 } 28 MoveToPrev()29 NodeType* MoveToPrev() { 30 if (!m_pRoot) 31 return nullptr; 32 if (!m_pCurrent) { 33 m_pCurrent = LastDescendant(m_pRoot); 34 return m_pCurrent; 35 } 36 NodeType* pSibling = PreviousSiblingWithinSubtree(m_pCurrent); 37 if (pSibling) { 38 m_pCurrent = LastDescendant(pSibling); 39 return m_pCurrent; 40 } 41 NodeType* pParent = ParentWithinSubtree(m_pCurrent); 42 if (pParent) { 43 m_pCurrent = pParent; 44 return m_pCurrent; 45 } 46 return nullptr; 47 } 48 MoveToNext()49 NodeType* MoveToNext() { 50 if (!m_pRoot || !m_pCurrent) 51 return nullptr; 52 NodeType* pChild = TraverseStrategy::GetFirstChild(m_pCurrent); 53 if (pChild) { 54 m_pCurrent = pChild; 55 return m_pCurrent; 56 } 57 return SkipChildrenAndMoveToNext(); 58 } 59 SkipChildrenAndMoveToNext()60 NodeType* SkipChildrenAndMoveToNext() { 61 if (!m_pRoot) 62 return nullptr; 63 NodeType* pNode = m_pCurrent; 64 while (pNode) { 65 NodeType* pSibling = NextSiblingWithinSubtree(pNode); 66 if (pSibling) { 67 m_pCurrent = pSibling; 68 return m_pCurrent; 69 } 70 pNode = ParentWithinSubtree(pNode); 71 } 72 m_pCurrent = nullptr; 73 return m_pCurrent; 74 } 75 76 private: RootReachableFromNode(NodeType * pNode)77 bool RootReachableFromNode(NodeType* pNode) { 78 if (!pNode) 79 return false; 80 if (pNode == m_pRoot) 81 return true; 82 return RootReachableFromNode(TraverseStrategy::GetParent(pNode)); 83 } 84 ParentWithinSubtree(NodeType * pNode)85 NodeType* ParentWithinSubtree(NodeType* pNode) { 86 if (!pNode || pNode == m_pRoot) 87 return nullptr; 88 return TraverseStrategy::GetParent(pNode); 89 } 90 NextSiblingWithinSubtree(NodeType * pNode)91 NodeType* NextSiblingWithinSubtree(NodeType* pNode) { 92 if (pNode == m_pRoot) 93 return nullptr; 94 return TraverseStrategy::GetNextSibling(pNode); 95 } 96 PreviousSiblingWithinSubtree(NodeType * pNode)97 NodeType* PreviousSiblingWithinSubtree(NodeType* pNode) { 98 NodeType* pParent = ParentWithinSubtree(pNode); 99 if (!pParent) 100 return nullptr; 101 NodeType* pCurrent = TraverseStrategy::GetFirstChild(pParent); 102 NodeType* pPrevious = nullptr; 103 while (pCurrent != pNode) { 104 pPrevious = pCurrent; 105 pCurrent = TraverseStrategy::GetNextSibling(pCurrent); 106 } 107 return pPrevious; 108 } 109 LastChild(NodeType * pNode)110 NodeType* LastChild(NodeType* pNode) { 111 NodeType* pPrevious = nullptr; 112 NodeType* pChild = TraverseStrategy::GetFirstChild(pNode); 113 while (pChild) { 114 pPrevious = pChild; 115 pChild = NextSiblingWithinSubtree(pChild); 116 } 117 return pPrevious; 118 } 119 LastDescendant(NodeType * pNode)120 NodeType* LastDescendant(NodeType* pNode) { 121 NodeType* pChild = LastChild(pNode); 122 return pChild ? LastDescendant(pChild) : pNode; 123 } 124 125 NodeType* m_pRoot; 126 NodeType* m_pCurrent; 127 }; 128 129 #endif // XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_ 130