Move code out of xfa_utils

This CL splits the node template out of xfa_utils into its own file. The
XFA_ByteStringToDouble method was moved to the only calling file.

Change-Id: I85fb2dfa3afc4a675ec69574e32d643c0dca731f
Reviewed-on: https://pdfium-review.googlesource.com/18490
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 3a62b70..3b7cabb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1850,6 +1850,7 @@
       "xfa/fxfa/parser/cxfa_node.h",
       "xfa/fxfa/parser/cxfa_nodehelper.cpp",
       "xfa/fxfa/parser/cxfa_nodehelper.h",
+      "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h",
       "xfa/fxfa/parser/cxfa_nodelist.cpp",
       "xfa/fxfa/parser/cxfa_nodelist.h",
       "xfa/fxfa/parser/cxfa_nodelocale.cpp",
@@ -2016,6 +2017,7 @@
       "xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp",
       "xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp",
       "xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp",
+      "xfa/fxfa/parser/cxfa_nodeiteratortemplate_unittest.cpp",
       "xfa/fxfa/parser/xfa_utils_unittest.cpp",
     ]
   }
diff --git a/fxjs/cfxjse_formcalc_context.cpp b/fxjs/cfxjse_formcalc_context.cpp
index 55fab55..30fa187 100644
--- a/fxjs/cfxjse_formcalc_context.cpp
+++ b/fxjs/cfxjse_formcalc_context.cpp
@@ -532,6 +532,90 @@
   return bsStr;
 }
 
+double ByteStringToDouble(const ByteStringView& szStringVal) {
+  WideString wsValue = WideString::FromUTF8(szStringVal);
+  wsValue.TrimLeft();
+  wsValue.TrimRight();
+
+  int32_t cc = 0;
+  bool bNegative = false;
+
+  const wchar_t* str = wsValue.c_str();
+  int32_t len = wsValue.GetLength();
+  if (str[0] == '+') {
+    cc++;
+  } else if (str[0] == '-') {
+    bNegative = true;
+    cc++;
+  }
+
+  int32_t nIntegralLen = 0;
+  int64_t nIntegral = 0;
+  while (cc < len) {
+    if (str[cc] == '.' || str[cc] == 'E' || str[cc] == 'e' ||
+        nIntegralLen > 17) {
+      break;
+    }
+    if (!FXSYS_isDecimalDigit(str[cc])) {
+      return 0;
+    }
+    nIntegral = nIntegral * 10 + str[cc] - '0';
+    cc++;
+    nIntegralLen++;
+  }
+  nIntegral = bNegative ? -nIntegral : nIntegral;
+
+  int32_t scale = 0;
+  double fraction = 0.0;
+  uint32_t dwFractional = 0;
+  if (cc < len && str[cc] == '.') {
+    cc++;
+    while (cc < len) {
+      fraction += XFA_GetFractionalScale(scale) * (str[cc] - '0');
+      scale++;
+      cc++;
+      if (cc == len)
+        break;
+      if (scale == XFA_GetMaxFractionalScale() || str[cc] == 'E' ||
+          str[cc] == 'e') {
+        break;
+      }
+      if (!FXSYS_isDecimalDigit(str[cc]))
+        return 0;
+    }
+    dwFractional = static_cast<uint32_t>(fraction * 4294967296.0);
+  }
+
+  int32_t nExponent = 0;
+  bool bExpSign = false;
+  if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
+    cc++;
+    if (cc < len) {
+      if (str[cc] == '+') {
+        cc++;
+      } else if (str[cc] == '-') {
+        bExpSign = true;
+        cc++;
+      }
+    }
+    while (cc < len) {
+      if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]))
+        return 0;
+
+      nExponent = nExponent * 10 + str[cc] - '0';
+      cc++;
+    }
+    nExponent = bExpSign ? -nExponent : nExponent;
+  }
+
+  double dValue = dwFractional / 4294967296.0;
+  dValue = nIntegral + (nIntegral >= 0 ? dValue : -dValue);
+  if (nExponent != 0)
+    dValue *= FXSYS_pow(10, static_cast<float>(nExponent));
+
+  return dValue;
+}
+
 }  // namespace
 
 // static
@@ -6005,8 +6089,10 @@
     GetObjectDefaultValue(arg, newPropertyValue.get());
     return ValueToFloat(pThis, newPropertyValue.get());
   }
-  if (arg->IsString())
-    return (float)XFA_ByteStringToDouble(arg->ToString().AsStringView());
+  if (arg->IsString()) {
+    return static_cast<float>(
+        ByteStringToDouble(arg->ToString().AsStringView()));
+  }
   if (arg->IsUndefined())
     return 0;
 
@@ -6040,7 +6126,7 @@
     return ValueToDouble(pThis, newPropertyValue.get());
   }
   if (arg->IsString())
-    return XFA_ByteStringToDouble(arg->ToString().AsStringView());
+    return ByteStringToDouble(arg->ToString().AsStringView());
   if (arg->IsUndefined())
     return 0;
   return arg->ToDouble();
diff --git a/fxjs/cjx_layoutpseudomodel.cpp b/fxjs/cjx_layoutpseudomodel.cpp
index 79e7fc8..9767c15 100644
--- a/fxjs/cjx_layoutpseudomodel.cpp
+++ b/fxjs/cjx_layoutpseudomodel.cpp
@@ -21,8 +21,8 @@
 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_contentlayoutitem.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
 
 CJX_LayoutPseudoModel::CJX_LayoutPseudoModel(CScript_LayoutPseudoModel* model)
     : CJX_Object(model) {}
diff --git a/xfa/fxfa/cxfa_ffdatetimeedit.cpp b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
index 65c32d5..54878ae 100644
--- a/xfa/fxfa/cxfa_ffdatetimeedit.cpp
+++ b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
@@ -15,6 +15,7 @@
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
 
 CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_WidgetAcc* pDataAcc)
     : CXFA_FFTextEdit(pDataAcc) {}
diff --git a/xfa/fxfa/cxfa_ffnumericedit.cpp b/xfa/fxfa/cxfa_ffnumericedit.cpp
index d6e1def..b8e9a1c 100644
--- a/xfa/fxfa/cxfa_ffnumericedit.cpp
+++ b/xfa/fxfa/cxfa_ffnumericedit.cpp
@@ -13,6 +13,7 @@
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
 
 CXFA_FFNumericEdit::CXFA_FFNumericEdit(CXFA_WidgetAcc* pDataAcc)
     : CXFA_FFTextEdit(pDataAcc) {}
diff --git a/xfa/fxfa/cxfa_ffpageview.h b/xfa/fxfa/cxfa_ffpageview.h
index f997885..b33e25f 100644
--- a/xfa/fxfa/cxfa_ffpageview.h
+++ b/xfa/fxfa/cxfa_ffpageview.h
@@ -12,8 +12,8 @@
 
 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
 
 class CXFA_FFWidget;
 class CXFA_FFDocView;
diff --git a/xfa/fxfa/cxfa_textprovider.cpp b/xfa/fxfa/cxfa_textprovider.cpp
index 165bc09..d4ef353 100644
--- a/xfa/fxfa/cxfa_textprovider.cpp
+++ b/xfa/fxfa/cxfa_textprovider.cpp
@@ -31,6 +31,7 @@
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
 
 CXFA_Node* CXFA_TextProvider::GetTextNode(bool& bRichText) {
   bRichText = false;
diff --git a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
index 189a466..c30c8dd 100644
--- a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
+++ b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
@@ -23,6 +23,7 @@
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 #include "xfa/fxfa/parser/cxfa_occurdata.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
diff --git a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
index 57d71ff..4ecbd04 100644
--- a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
+++ b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
@@ -17,6 +17,7 @@
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h"
@@ -24,7 +25,6 @@
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
 
 namespace {
 
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index c906d26..07d9f84 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -32,10 +32,12 @@
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 #include "xfa/fxfa/parser/cxfa_occurdata.h"
 #include "xfa/fxfa/parser/cxfa_simple_parser.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
 #include "xfa/fxfa/parser/xfa_basic_data.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
 
 namespace {
 
diff --git a/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h b/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h
new file mode 100644
index 0000000..214f38e
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h
@@ -0,0 +1,129 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// 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_
+
+template <class NodeType, class TraverseStrategy>
+class CXFA_NodeIteratorTemplate {
+ public:
+  explicit CXFA_NodeIteratorTemplate(NodeType* pRoot)
+      : m_pRoot(pRoot), m_pCurrent(pRoot) {}
+
+  NodeType* GetRoot() const { return m_pRoot; }
+  NodeType* GetCurrent() const { return 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(m_pRoot);
+      return m_pCurrent;
+    }
+    NodeType* pSibling = PreviousSiblingWithinSubtree(m_pCurrent);
+    if (pSibling) {
+      m_pCurrent = LastDescendant(pSibling);
+      return m_pCurrent;
+    }
+    NodeType* pParent = ParentWithinSubtree(m_pCurrent);
+    if (pParent) {
+      m_pCurrent = pParent;
+      return m_pCurrent;
+    }
+    return nullptr;
+  }
+
+  NodeType* MoveToNext() {
+    if (!m_pRoot || !m_pCurrent)
+      return nullptr;
+    NodeType* pChild = TraverseStrategy::GetFirstChild(m_pCurrent);
+    if (pChild) {
+      m_pCurrent = pChild;
+      return m_pCurrent;
+    }
+    return SkipChildrenAndMoveToNext();
+  }
+
+  NodeType* SkipChildrenAndMoveToNext() {
+    if (!m_pRoot)
+      return nullptr;
+    NodeType* pNode = m_pCurrent;
+    while (pNode) {
+      NodeType* pSibling = NextSiblingWithinSubtree(pNode);
+      if (pSibling) {
+        m_pCurrent = pSibling;
+        return m_pCurrent;
+      }
+      pNode = ParentWithinSubtree(pNode);
+    }
+    m_pCurrent = nullptr;
+    return m_pCurrent;
+  }
+
+ private:
+  bool RootReachableFromNode(NodeType* pNode) {
+    if (!pNode)
+      return false;
+    if (pNode == m_pRoot)
+      return true;
+    return RootReachableFromNode(TraverseStrategy::GetParent(pNode));
+  }
+
+  NodeType* ParentWithinSubtree(NodeType* pNode) {
+    if (!pNode || pNode == m_pRoot)
+      return nullptr;
+    return TraverseStrategy::GetParent(pNode);
+  }
+
+  NodeType* NextSiblingWithinSubtree(NodeType* pNode) {
+    if (pNode == m_pRoot)
+      return nullptr;
+    return TraverseStrategy::GetNextSibling(pNode);
+  }
+
+  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;
+  }
+
+  NodeType* m_pRoot;
+  NodeType* m_pCurrent;
+};
+
+#endif  // XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_
diff --git a/xfa/fxfa/parser/cxfa_nodeiteratortemplate_unittest.cpp b/xfa/fxfa/parser/cxfa_nodeiteratortemplate_unittest.cpp
new file mode 100644
index 0000000..114bed0
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_nodeiteratortemplate_unittest.cpp
@@ -0,0 +1,257 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
+
+#include <memory>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/test_support.h"
+#include "third_party/base/ptr_util.h"
+
+class CXFA_NodeIteratorTemplateTest : public testing::Test {
+ public:
+  class Node {
+   public:
+    class Strategy {
+     public:
+      static Node* GetFirstChild(Node* pNode) {
+        return pNode && !pNode->children_.empty() ? pNode->children_.front()
+                                                  : nullptr;
+      }
+      static Node* GetNextSibling(Node* pNode) {
+        return pNode ? pNode->next_sibling_ : nullptr;
+      }
+      static Node* GetParent(Node* pNode) {
+        return pNode ? pNode->parent_ : nullptr;
+      }
+    };
+
+    explicit Node(Node* parent) : parent_(parent), next_sibling_(nullptr) {
+      if (parent) {
+        if (!parent->children_.empty())
+          parent->children_.back()->next_sibling_ = this;
+        parent->children_.push_back(this);
+      }
+    }
+
+   private:
+    Node* parent_;
+    Node* next_sibling_;
+    std::vector<Node*> children_;
+  };
+
+  using Iterator = CXFA_NodeIteratorTemplate<Node, Node::Strategy>;
+
+  // Builds a tree along the lines of:
+  //
+  //   root
+  //   |
+  //   child1--child2
+  //            |
+  //            child3------------child7--child9
+  //            |                 |
+  //            child4--child6    child8
+  //            |
+  //            child5
+  //
+  void SetUp() override {
+    root_ = pdfium::MakeUnique<Node>(nullptr);
+    child1_ = pdfium::MakeUnique<Node>(root_.get());
+    child2_ = pdfium::MakeUnique<Node>(root_.get());
+    child3_ = pdfium::MakeUnique<Node>(child2_.get());
+    child4_ = pdfium::MakeUnique<Node>(child3_.get());
+    child5_ = pdfium::MakeUnique<Node>(child4_.get());
+    child6_ = pdfium::MakeUnique<Node>(child3_.get());
+    child7_ = pdfium::MakeUnique<Node>(child2_.get());
+    child8_ = pdfium::MakeUnique<Node>(child7_.get());
+    child9_ = pdfium::MakeUnique<Node>(child2_.get());
+  }
+
+  Node* root() const { return root_.get(); }
+  Node* child1() const { return child1_.get(); }
+  Node* child2() const { return child2_.get(); }
+  Node* child3() const { return child3_.get(); }
+  Node* child4() const { return child4_.get(); }
+  Node* child5() const { return child5_.get(); }
+  Node* child6() const { return child6_.get(); }
+  Node* child7() const { return child7_.get(); }
+  Node* child8() const { return child8_.get(); }
+  Node* child9() const { return child9_.get(); }
+
+ protected:
+  std::unique_ptr<Node> root_;
+  std::unique_ptr<Node> child1_;
+  std::unique_ptr<Node> child2_;
+  std::unique_ptr<Node> child3_;
+  std::unique_ptr<Node> child4_;
+  std::unique_ptr<Node> child5_;
+  std::unique_ptr<Node> child6_;
+  std::unique_ptr<Node> child7_;
+  std::unique_ptr<Node> child8_;
+  std::unique_ptr<Node> child9_;
+};
+
+TEST_F(CXFA_NodeIteratorTemplateTest, Empty) {
+  Iterator iter(nullptr);
+  EXPECT_EQ(nullptr, iter.GetRoot());
+  EXPECT_EQ(nullptr, iter.GetCurrent());
+  EXPECT_EQ(nullptr, iter.MoveToNext());
+  EXPECT_EQ(nullptr, iter.MoveToPrev());
+  EXPECT_EQ(nullptr, iter.SkipChildrenAndMoveToNext());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, Root) {
+  Iterator iter(root());
+  EXPECT_EQ(root(), iter.GetRoot());
+  EXPECT_EQ(root(), iter.GetCurrent());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, Current) {
+  Iterator iter(root());
+  iter.SetCurrent(child1());
+  EXPECT_EQ(root(), iter.GetRoot());
+  EXPECT_EQ(child1(), iter.GetCurrent());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, CurrentOutsideRootDisallowed) {
+  Iterator iter(child1());
+  iter.SetCurrent(root());
+  EXPECT_EQ(child1(), iter.GetRoot());
+  EXPECT_EQ(nullptr, iter.GetCurrent());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, CurrentNull) {
+  Iterator iter(root());
+  EXPECT_EQ(child1(), iter.MoveToNext());
+
+  iter.SetCurrent(nullptr);
+  EXPECT_EQ(nullptr, iter.GetCurrent());
+
+  EXPECT_EQ(nullptr, iter.MoveToNext());
+  EXPECT_EQ(nullptr, iter.GetCurrent());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, MoveToPrev) {
+  Iterator iter(root());
+  iter.SetCurrent(child9());
+
+  EXPECT_EQ(child8(), iter.MoveToPrev());
+  EXPECT_EQ(child8(), iter.GetCurrent());
+
+  EXPECT_EQ(child7(), iter.MoveToPrev());
+  EXPECT_EQ(child7(), iter.GetCurrent());
+
+  EXPECT_EQ(child6(), iter.MoveToPrev());
+  EXPECT_EQ(child6(), iter.GetCurrent());
+
+  EXPECT_EQ(child5(), iter.MoveToPrev());
+  EXPECT_EQ(child5(), iter.GetCurrent());
+
+  EXPECT_EQ(child4(), iter.MoveToPrev());
+  EXPECT_EQ(child4(), iter.GetCurrent());
+
+  EXPECT_EQ(child3(), iter.MoveToPrev());
+  EXPECT_EQ(child3(), iter.GetCurrent());
+
+  EXPECT_EQ(child2(), iter.MoveToPrev());
+  EXPECT_EQ(child2(), iter.GetCurrent());
+
+  EXPECT_EQ(child1(), iter.MoveToPrev());
+  EXPECT_EQ(child1(), iter.GetCurrent());
+
+  EXPECT_EQ(root(), iter.MoveToPrev());
+  EXPECT_EQ(root(), iter.GetCurrent());
+
+  EXPECT_EQ(nullptr, iter.MoveToPrev());
+  EXPECT_EQ(root(), iter.GetCurrent());
+
+  EXPECT_EQ(nullptr, iter.MoveToPrev());
+  EXPECT_EQ(root(), iter.GetCurrent());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, MoveToNext) {
+  Iterator iter(root());
+  iter.SetCurrent(child2());
+
+  EXPECT_EQ(child3(), iter.MoveToNext());
+  EXPECT_EQ(child3(), iter.GetCurrent());
+
+  EXPECT_EQ(child4(), iter.MoveToNext());
+  EXPECT_EQ(child4(), iter.GetCurrent());
+
+  EXPECT_EQ(child5(), iter.MoveToNext());
+  EXPECT_EQ(child5(), iter.GetCurrent());
+
+  EXPECT_EQ(child6(), iter.MoveToNext());
+  EXPECT_EQ(child6(), iter.GetCurrent());
+
+  EXPECT_EQ(child7(), iter.MoveToNext());
+  EXPECT_EQ(child7(), iter.GetCurrent());
+
+  EXPECT_EQ(child8(), iter.MoveToNext());
+  EXPECT_EQ(child8(), iter.GetCurrent());
+
+  EXPECT_EQ(child9(), iter.MoveToNext());
+  EXPECT_EQ(child9(), iter.GetCurrent());
+
+  EXPECT_EQ(nullptr, iter.MoveToNext());
+  EXPECT_EQ(nullptr, iter.GetCurrent());
+
+  EXPECT_EQ(nullptr, iter.MoveToNext());
+  EXPECT_EQ(nullptr, iter.GetCurrent());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, SkipChildrenAndMoveToNext) {
+  Iterator iter(root());
+  iter.SetCurrent(child3());
+  EXPECT_EQ(child7(), iter.SkipChildrenAndMoveToNext());
+  EXPECT_EQ(child9(), iter.SkipChildrenAndMoveToNext());
+  EXPECT_EQ(nullptr, iter.SkipChildrenAndMoveToNext());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, BackAndForth) {
+  Iterator iter(root());
+  EXPECT_EQ(child1(), iter.MoveToNext());
+  EXPECT_EQ(child2(), iter.MoveToNext());
+  EXPECT_EQ(child3(), iter.MoveToNext());
+  EXPECT_EQ(child4(), iter.MoveToNext());
+  EXPECT_EQ(child5(), iter.MoveToNext());
+  EXPECT_EQ(child4(), iter.MoveToPrev());
+  EXPECT_EQ(child3(), iter.MoveToPrev());
+  EXPECT_EQ(child2(), iter.MoveToPrev());
+  EXPECT_EQ(child1(), iter.MoveToPrev());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, NextFromBeforeTheBeginning) {
+  Iterator iter(root());
+  EXPECT_EQ(nullptr, iter.MoveToPrev());
+  EXPECT_EQ(root(), iter.GetCurrent());
+  EXPECT_EQ(child1(), iter.MoveToNext());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, PrevFromAfterTheEnd) {
+  Iterator iter(root());
+  iter.SetCurrent(child9());
+  EXPECT_EQ(nullptr, iter.MoveToNext());
+  EXPECT_EQ(child9(), iter.MoveToPrev());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, ChildAsRootPrev) {
+  Iterator iter(child3());
+  EXPECT_EQ(nullptr, iter.MoveToPrev());
+
+  iter.SetCurrent(child4());
+  EXPECT_EQ(child3(), iter.MoveToPrev());
+  EXPECT_EQ(nullptr, iter.MoveToPrev());
+}
+
+TEST_F(CXFA_NodeIteratorTemplateTest, ChildAsRootNext) {
+  Iterator iter(child3());
+  iter.SetCurrent(child4());
+  EXPECT_EQ(child5(), iter.MoveToNext());
+  EXPECT_EQ(child6(), iter.MoveToNext());
+  EXPECT_EQ(nullptr, iter.MoveToNext());
+}
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h b/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h
index d507c26..ce6463c 100644
--- a/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h
+++ b/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h
@@ -8,7 +8,7 @@
 #define XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_XFACONTAINERNODE_H_
 
 #include "xfa/fxfa/parser/cxfa_node.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 
 class CXFA_TraverseStrategy_XFAContainerNode {
  public:
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h b/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h
index b6fb156..7fab43c 100644
--- a/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h
+++ b/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h
@@ -7,7 +7,7 @@
 #ifndef XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_XFANODE_H_
 #define XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_XFANODE_H_
 
-#include "xfa/fxfa/parser/xfa_utils.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 
 class CXFA_TraverseStrategy_XFANode {
  public:
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
index 128ad7b..94c82f8 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
@@ -19,6 +19,7 @@
 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
 #include "xfa/fxfa/parser/cxfa_occurdata.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
diff --git a/xfa/fxfa/parser/xfa_utils.cpp b/xfa/fxfa/parser/xfa_utils.cpp
index 5bdfe58..588246f 100644
--- a/xfa/fxfa/parser/xfa_utils.cpp
+++ b/xfa/fxfa/parser/xfa_utils.cpp
@@ -39,85 +39,6 @@
                                   0.000000000000001,
                                   0.0000000000000001};
 
-double WideStringToDouble(const WideString& wsStringVal) {
-  WideString wsValue = wsStringVal;
-  wsValue.TrimLeft();
-  wsValue.TrimRight();
-  int64_t nIntegral = 0;
-  uint32_t dwFractional = 0;
-  int32_t nExponent = 0;
-  int32_t cc = 0;
-  bool bNegative = false;
-  bool bExpSign = false;
-  const wchar_t* str = wsValue.c_str();
-  int32_t len = wsValue.GetLength();
-  if (str[0] == '+') {
-    cc++;
-  } else if (str[0] == '-') {
-    bNegative = true;
-    cc++;
-  }
-  int32_t nIntegralLen = 0;
-  while (cc < len) {
-    if (str[cc] == '.' || str[cc] == 'E' || str[cc] == 'e' ||
-        nIntegralLen > 17) {
-      break;
-    }
-    if (!FXSYS_isDecimalDigit(str[cc])) {
-      return 0;
-    }
-    nIntegral = nIntegral * 10 + str[cc] - '0';
-    cc++;
-    nIntegralLen++;
-  }
-  nIntegral = bNegative ? -nIntegral : nIntegral;
-  int32_t scale = 0;
-  double fraction = 0.0;
-  if (cc < len && str[cc] == '.') {
-    cc++;
-    while (cc < len) {
-      fraction += XFA_GetFractionalScale(scale) * (str[cc] - '0');
-      scale++;
-      cc++;
-      if (cc == len)
-        break;
-      if (scale == XFA_GetMaxFractionalScale() || str[cc] == 'E' ||
-          str[cc] == 'e') {
-        break;
-      }
-      if (!FXSYS_isDecimalDigit(str[cc]))
-        return 0;
-    }
-    dwFractional = static_cast<uint32_t>(fraction * 4294967296.0);
-  }
-  if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
-    cc++;
-    if (cc < len) {
-      if (str[cc] == '+') {
-        cc++;
-      } else if (str[cc] == '-') {
-        bExpSign = true;
-        cc++;
-      }
-    }
-    while (cc < len) {
-      if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]))
-        return 0;
-
-      nExponent = nExponent * 10 + str[cc] - '0';
-      cc++;
-    }
-    nExponent = bExpSign ? -nExponent : nExponent;
-  }
-
-  double dValue = dwFractional / 4294967296.0;
-  dValue = nIntegral + (nIntegral >= 0 ? dValue : -dValue);
-  if (nExponent != 0)
-    dValue *= FXSYS_pow(10, static_cast<float>(nExponent));
-
-  return dValue;
-}
-
 }  // namespace
 
 double XFA_GetFractionalScale(uint32_t idx) {
@@ -228,11 +149,6 @@
   return bRet;
 }
 
-double XFA_ByteStringToDouble(const ByteStringView& szStringVal) {
-  WideString wsValue = WideString::FromUTF8(szStringVal);
-  return WideStringToDouble(wsValue);
-}
-
 int32_t XFA_MapRotation(int32_t nRotation) {
   nRotation = nRotation % 360;
   nRotation = nRotation < 0 ? nRotation + 360 : nRotation;
diff --git a/xfa/fxfa/parser/xfa_utils.h b/xfa/fxfa/parser/xfa_utils.h
index cfa27bb..b00f7aa 100644
--- a/xfa/fxfa/parser/xfa_utils.h
+++ b/xfa/fxfa/parser/xfa_utils.h
@@ -23,127 +23,7 @@
                                                 const WideString& wsQualifier,
                                                 WideString* wsNamespaceURI);
 
-template <class NodeType, class TraverseStrategy>
-class CXFA_NodeIteratorTemplate {
- public:
-  explicit CXFA_NodeIteratorTemplate(NodeType* pRoot)
-      : m_pRoot(pRoot), m_pCurrent(pRoot) {}
-
-  NodeType* GetRoot() const { return m_pRoot; }
-  NodeType* GetCurrent() const { return 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(m_pRoot);
-      return m_pCurrent;
-    }
-    NodeType* pSibling = PreviousSiblingWithinSubtree(m_pCurrent);
-    if (pSibling) {
-      m_pCurrent = LastDescendant(pSibling);
-      return m_pCurrent;
-    }
-    NodeType* pParent = ParentWithinSubtree(m_pCurrent);
-    if (pParent) {
-      m_pCurrent = pParent;
-      return m_pCurrent;
-    }
-    return nullptr;
-  }
-
-  NodeType* MoveToNext() {
-    if (!m_pRoot || !m_pCurrent)
-      return nullptr;
-    NodeType* pChild = TraverseStrategy::GetFirstChild(m_pCurrent);
-    if (pChild) {
-      m_pCurrent = pChild;
-      return m_pCurrent;
-    }
-    return SkipChildrenAndMoveToNext();
-  }
-
-  NodeType* SkipChildrenAndMoveToNext() {
-    if (!m_pRoot)
-      return nullptr;
-    NodeType* pNode = m_pCurrent;
-    while (pNode) {
-      NodeType* pSibling = NextSiblingWithinSubtree(pNode);
-      if (pSibling) {
-        m_pCurrent = pSibling;
-        return m_pCurrent;
-      }
-      pNode = ParentWithinSubtree(pNode);
-    }
-    m_pCurrent = nullptr;
-    return m_pCurrent;
-  }
-
- private:
-  bool RootReachableFromNode(NodeType* pNode) {
-    if (!pNode)
-      return false;
-    if (pNode == m_pRoot)
-      return true;
-    return RootReachableFromNode(TraverseStrategy::GetParent(pNode));
-  }
-
-  NodeType* ParentWithinSubtree(NodeType* pNode) {
-    if (!pNode || pNode == m_pRoot)
-      return nullptr;
-    return TraverseStrategy::GetParent(pNode);
-  }
-
-  NodeType* NextSiblingWithinSubtree(NodeType* pNode) {
-    if (pNode == m_pRoot)
-      return nullptr;
-    return TraverseStrategy::GetNextSibling(pNode);
-  }
-
-  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;
-  }
-
-  NodeType* m_pRoot;
-  NodeType* m_pCurrent;
-};
-
 CXFA_LocaleValue XFA_GetLocaleValue(CXFA_WidgetData* pWidgetData);
-double XFA_ByteStringToDouble(const ByteStringView& szStringVal);
 int32_t XFA_MapRotation(int32_t nRotation);
 
 bool XFA_RecognizeRichText(CFX_XMLElement* pRichTextXMLNode);
diff --git a/xfa/fxfa/parser/xfa_utils_unittest.cpp b/xfa/fxfa/parser/xfa_utils_unittest.cpp
index ab344c4..bd2c89d 100644
--- a/xfa/fxfa/parser/xfa_utils_unittest.cpp
+++ b/xfa/fxfa/parser/xfa_utils_unittest.cpp
@@ -4,12 +4,8 @@
 
 #include "xfa/fxfa/parser/xfa_utils.h"
 
-#include <memory>
-#include <vector>
-
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/test_support.h"
-#include "third_party/base/ptr_util.h"
 
 TEST(XfaUtilsImpTest, XFA_MapRotation) {
   struct TestCase {
@@ -27,251 +23,6 @@
   }
 }
 
-class XFANodeIteratorTest : public testing::Test {
- public:
-  class Node {
-   public:
-    class Strategy {
-     public:
-      static Node* GetFirstChild(Node* pNode) {
-        return pNode && !pNode->children_.empty() ? pNode->children_.front()
-                                                  : nullptr;
-      }
-      static Node* GetNextSibling(Node* pNode) {
-        return pNode ? pNode->next_sibling_ : nullptr;
-      }
-      static Node* GetParent(Node* pNode) {
-        return pNode ? pNode->parent_ : nullptr;
-      }
-    };
-
-    explicit Node(Node* parent) : parent_(parent), next_sibling_(nullptr) {
-      if (parent) {
-        if (!parent->children_.empty())
-          parent->children_.back()->next_sibling_ = this;
-        parent->children_.push_back(this);
-      }
-    }
-
-   private:
-    Node* parent_;
-    Node* next_sibling_;
-    std::vector<Node*> children_;
-  };
-
-  using Iterator = CXFA_NodeIteratorTemplate<Node, Node::Strategy>;
-
-  // Builds a tree along the lines of:
-  //
-  //   root
-  //   |
-  //   child1--child2
-  //            |
-  //            child3------------child7--child9
-  //            |                 |
-  //            child4--child6    child8
-  //            |
-  //            child5
-  //
-  void SetUp() override {
-    root_ = pdfium::MakeUnique<Node>(nullptr);
-    child1_ = pdfium::MakeUnique<Node>(root_.get());
-    child2_ = pdfium::MakeUnique<Node>(root_.get());
-    child3_ = pdfium::MakeUnique<Node>(child2_.get());
-    child4_ = pdfium::MakeUnique<Node>(child3_.get());
-    child5_ = pdfium::MakeUnique<Node>(child4_.get());
-    child6_ = pdfium::MakeUnique<Node>(child3_.get());
-    child7_ = pdfium::MakeUnique<Node>(child2_.get());
-    child8_ = pdfium::MakeUnique<Node>(child7_.get());
-    child9_ = pdfium::MakeUnique<Node>(child2_.get());
-  }
-
-  Node* root() const { return root_.get(); }
-  Node* child1() const { return child1_.get(); }
-  Node* child2() const { return child2_.get(); }
-  Node* child3() const { return child3_.get(); }
-  Node* child4() const { return child4_.get(); }
-  Node* child5() const { return child5_.get(); }
-  Node* child6() const { return child6_.get(); }
-  Node* child7() const { return child7_.get(); }
-  Node* child8() const { return child8_.get(); }
-  Node* child9() const { return child9_.get(); }
-
- protected:
-  std::unique_ptr<Node> root_;
-  std::unique_ptr<Node> child1_;
-  std::unique_ptr<Node> child2_;
-  std::unique_ptr<Node> child3_;
-  std::unique_ptr<Node> child4_;
-  std::unique_ptr<Node> child5_;
-  std::unique_ptr<Node> child6_;
-  std::unique_ptr<Node> child7_;
-  std::unique_ptr<Node> child8_;
-  std::unique_ptr<Node> child9_;
-};
-
-TEST_F(XFANodeIteratorTest, Empty) {
-  Iterator iter(nullptr);
-  EXPECT_EQ(nullptr, iter.GetRoot());
-  EXPECT_EQ(nullptr, iter.GetCurrent());
-  EXPECT_EQ(nullptr, iter.MoveToNext());
-  EXPECT_EQ(nullptr, iter.MoveToPrev());
-  EXPECT_EQ(nullptr, iter.SkipChildrenAndMoveToNext());
-}
-
-TEST_F(XFANodeIteratorTest, Root) {
-  Iterator iter(root());
-  EXPECT_EQ(root(), iter.GetRoot());
-  EXPECT_EQ(root(), iter.GetCurrent());
-}
-
-TEST_F(XFANodeIteratorTest, Current) {
-  Iterator iter(root());
-  iter.SetCurrent(child1());
-  EXPECT_EQ(root(), iter.GetRoot());
-  EXPECT_EQ(child1(), iter.GetCurrent());
-}
-
-TEST_F(XFANodeIteratorTest, CurrentOutsideRootDisallowed) {
-  Iterator iter(child1());
-  iter.SetCurrent(root());
-  EXPECT_EQ(child1(), iter.GetRoot());
-  EXPECT_EQ(nullptr, iter.GetCurrent());
-}
-
-TEST_F(XFANodeIteratorTest, CurrentNull) {
-  Iterator iter(root());
-  EXPECT_EQ(child1(), iter.MoveToNext());
-
-  iter.SetCurrent(nullptr);
-  EXPECT_EQ(nullptr, iter.GetCurrent());
-
-  EXPECT_EQ(nullptr, iter.MoveToNext());
-  EXPECT_EQ(nullptr, iter.GetCurrent());
-}
-
-TEST_F(XFANodeIteratorTest, MoveToPrev) {
-  Iterator iter(root());
-  iter.SetCurrent(child9());
-
-  EXPECT_EQ(child8(), iter.MoveToPrev());
-  EXPECT_EQ(child8(), iter.GetCurrent());
-
-  EXPECT_EQ(child7(), iter.MoveToPrev());
-  EXPECT_EQ(child7(), iter.GetCurrent());
-
-  EXPECT_EQ(child6(), iter.MoveToPrev());
-  EXPECT_EQ(child6(), iter.GetCurrent());
-
-  EXPECT_EQ(child5(), iter.MoveToPrev());
-  EXPECT_EQ(child5(), iter.GetCurrent());
-
-  EXPECT_EQ(child4(), iter.MoveToPrev());
-  EXPECT_EQ(child4(), iter.GetCurrent());
-
-  EXPECT_EQ(child3(), iter.MoveToPrev());
-  EXPECT_EQ(child3(), iter.GetCurrent());
-
-  EXPECT_EQ(child2(), iter.MoveToPrev());
-  EXPECT_EQ(child2(), iter.GetCurrent());
-
-  EXPECT_EQ(child1(), iter.MoveToPrev());
-  EXPECT_EQ(child1(), iter.GetCurrent());
-
-  EXPECT_EQ(root(), iter.MoveToPrev());
-  EXPECT_EQ(root(), iter.GetCurrent());
-
-  EXPECT_EQ(nullptr, iter.MoveToPrev());
-  EXPECT_EQ(root(), iter.GetCurrent());
-
-  EXPECT_EQ(nullptr, iter.MoveToPrev());
-  EXPECT_EQ(root(), iter.GetCurrent());
-}
-
-TEST_F(XFANodeIteratorTest, MoveToNext) {
-  Iterator iter(root());
-  iter.SetCurrent(child2());
-
-  EXPECT_EQ(child3(), iter.MoveToNext());
-  EXPECT_EQ(child3(), iter.GetCurrent());
-
-  EXPECT_EQ(child4(), iter.MoveToNext());
-  EXPECT_EQ(child4(), iter.GetCurrent());
-
-  EXPECT_EQ(child5(), iter.MoveToNext());
-  EXPECT_EQ(child5(), iter.GetCurrent());
-
-  EXPECT_EQ(child6(), iter.MoveToNext());
-  EXPECT_EQ(child6(), iter.GetCurrent());
-
-  EXPECT_EQ(child7(), iter.MoveToNext());
-  EXPECT_EQ(child7(), iter.GetCurrent());
-
-  EXPECT_EQ(child8(), iter.MoveToNext());
-  EXPECT_EQ(child8(), iter.GetCurrent());
-
-  EXPECT_EQ(child9(), iter.MoveToNext());
-  EXPECT_EQ(child9(), iter.GetCurrent());
-
-  EXPECT_EQ(nullptr, iter.MoveToNext());
-  EXPECT_EQ(nullptr, iter.GetCurrent());
-
-  EXPECT_EQ(nullptr, iter.MoveToNext());
-  EXPECT_EQ(nullptr, iter.GetCurrent());
-}
-
-TEST_F(XFANodeIteratorTest, SkipChildrenAndMoveToNext) {
-  Iterator iter(root());
-  iter.SetCurrent(child3());
-  EXPECT_EQ(child7(), iter.SkipChildrenAndMoveToNext());
-  EXPECT_EQ(child9(), iter.SkipChildrenAndMoveToNext());
-  EXPECT_EQ(nullptr, iter.SkipChildrenAndMoveToNext());
-}
-
-TEST_F(XFANodeIteratorTest, BackAndForth) {
-  Iterator iter(root());
-  EXPECT_EQ(child1(), iter.MoveToNext());
-  EXPECT_EQ(child2(), iter.MoveToNext());
-  EXPECT_EQ(child3(), iter.MoveToNext());
-  EXPECT_EQ(child4(), iter.MoveToNext());
-  EXPECT_EQ(child5(), iter.MoveToNext());
-  EXPECT_EQ(child4(), iter.MoveToPrev());
-  EXPECT_EQ(child3(), iter.MoveToPrev());
-  EXPECT_EQ(child2(), iter.MoveToPrev());
-  EXPECT_EQ(child1(), iter.MoveToPrev());
-}
-
-TEST_F(XFANodeIteratorTest, NextFromBeforeTheBeginning) {
-  Iterator iter(root());
-  EXPECT_EQ(nullptr, iter.MoveToPrev());
-  EXPECT_EQ(root(), iter.GetCurrent());
-  EXPECT_EQ(child1(), iter.MoveToNext());
-}
-
-TEST_F(XFANodeIteratorTest, PrevFromAfterTheEnd) {
-  Iterator iter(root());
-  iter.SetCurrent(child9());
-  EXPECT_EQ(nullptr, iter.MoveToNext());
-  EXPECT_EQ(child9(), iter.MoveToPrev());
-}
-
-TEST_F(XFANodeIteratorTest, ChildAsRootPrev) {
-  Iterator iter(child3());
-  EXPECT_EQ(nullptr, iter.MoveToPrev());
-
-  iter.SetCurrent(child4());
-  EXPECT_EQ(child3(), iter.MoveToPrev());
-  EXPECT_EQ(nullptr, iter.MoveToPrev());
-}
-
-TEST_F(XFANodeIteratorTest, ChildAsRootNext) {
-  Iterator iter(child3());
-  iter.SetCurrent(child4());
-  EXPECT_EQ(child5(), iter.MoveToNext());
-  EXPECT_EQ(child6(), iter.MoveToNext());
-  EXPECT_EQ(nullptr, iter.MoveToNext());
-}
-
 TEST(XFAUtilsTest, GetAttributeByName) {
   EXPECT_EQ(nullptr, XFA_GetAttributeByName(L""));
   EXPECT_EQ(nullptr, XFA_GetAttributeByName(L"nonesuch"));